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/unicode.h"
44 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(file
);
49 HANDLE dos_handles
[DOS_TABLE_SIZE
];
51 /**************************************************************************
52 * Operations on file handles *
53 **************************************************************************/
55 /***********************************************************************
56 * FILE_InitProcessDosHandles
58 * Allocates the default DOS handles for a process. Called either by
59 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
61 static void FILE_InitProcessDosHandles( void )
63 static BOOL init_done
/* = FALSE */;
64 HANDLE cp
= GetCurrentProcess();
66 if (init_done
) return;
68 DuplicateHandle(cp
, GetStdHandle(STD_INPUT_HANDLE
), cp
, &dos_handles
[0],
69 0, TRUE
, DUPLICATE_SAME_ACCESS
);
70 DuplicateHandle(cp
, GetStdHandle(STD_OUTPUT_HANDLE
), cp
, &dos_handles
[1],
71 0, TRUE
, DUPLICATE_SAME_ACCESS
);
72 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[2],
73 0, TRUE
, DUPLICATE_SAME_ACCESS
);
74 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[3],
75 0, TRUE
, DUPLICATE_SAME_ACCESS
);
76 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[4],
77 0, TRUE
, DUPLICATE_SAME_ACCESS
);
81 /***********************************************************************
82 * GetOverlappedResult (KERNEL32.@)
84 * Check the result of an Asynchronous data transfer from a file.
87 * HANDLE hFile [in] handle of file to check on
88 * LPOVERLAPPED lpOverlapped [in/out] pointer to overlapped
89 * LPDWORD lpTransferred [in/out] number of bytes transferred
90 * BOOL bWait [in] wait for the transfer to complete ?
96 * If successful (and relevant) lpTransferred will hold the number of
97 * bytes transferred during the async operation.
101 * Currently only works for WaitCommEvent, ReadFile, WriteFile
102 * with communications ports.
105 BOOL WINAPI
GetOverlappedResult(HANDLE hFile
, LPOVERLAPPED lpOverlapped
,
106 LPDWORD lpTransferred
, BOOL bWait
)
110 TRACE("(%p %p %p %x)\n", hFile
, lpOverlapped
, lpTransferred
, bWait
);
112 if (lpOverlapped
==NULL
)
114 ERR("lpOverlapped was null\n");
117 if (!lpOverlapped
->hEvent
)
119 ERR("lpOverlapped->hEvent was null\n");
126 TRACE("waiting on %p\n",lpOverlapped
);
127 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, INFINITE
, TRUE
);
128 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
129 } while (r
==STATUS_USER_APC
);
131 else if ( lpOverlapped
->Internal
== STATUS_PENDING
)
133 /* Wait in order to give APCs a chance to run. */
134 /* This is cheating, so we must set the event again in case of success -
135 it may be a non-manual reset event. */
137 TRACE("waiting on %p\n",lpOverlapped
);
138 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, 0, TRUE
);
139 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
140 } while (r
==STATUS_USER_APC
);
141 if ( r
== WAIT_OBJECT_0
)
142 NtSetEvent ( lpOverlapped
->hEvent
, NULL
);
146 *lpTransferred
= lpOverlapped
->InternalHigh
;
148 switch ( lpOverlapped
->Internal
)
153 SetLastError ( ERROR_IO_INCOMPLETE
);
154 if ( bWait
) ERR ("PENDING status after waiting!\n");
157 SetLastError ( RtlNtStatusToDosError ( lpOverlapped
->Internal
) );
162 /***********************************************************************
163 * CancelIo (KERNEL32.@)
165 BOOL WINAPI
CancelIo(HANDLE handle
)
167 async_private
*ovp
,*t
;
169 TRACE("handle = %p\n",handle
);
171 for (ovp
= NtCurrentTeb()->pending_list
; ovp
; ovp
= t
)
174 if ( ovp
->handle
== handle
)
175 cancel_async ( ovp
);
181 /***********************************************************************
182 * _hread (KERNEL32.@)
184 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
186 return _lread( hFile
, buffer
, count
);
190 /***********************************************************************
191 * _hwrite (KERNEL32.@)
193 * experimentation yields that _lwrite:
194 * o truncates the file at the current position with
196 * o returns 0 on a 0 length write
197 * o works with console handles
200 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
204 TRACE("%d %p %ld\n", handle
, buffer
, count
);
208 /* Expand or truncate at current position */
209 if (!SetEndOfFile( (HANDLE
)handle
)) return HFILE_ERROR
;
212 if (!WriteFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
))
218 /***********************************************************************
219 * _lclose (KERNEL32.@)
221 HFILE WINAPI
_lclose( HFILE hFile
)
223 TRACE("handle %d\n", hFile
);
224 return CloseHandle( (HANDLE
)hFile
) ? 0 : HFILE_ERROR
;
228 /***********************************************************************
229 * _lcreat (KERNEL32.@)
231 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
233 /* Mask off all flags not explicitly allowed by the doc */
234 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
235 TRACE("%s %02x\n", path
, attr
);
236 return (HFILE
)CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
237 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
238 CREATE_ALWAYS
, attr
, 0 );
242 /***********************************************************************
243 * _lopen (KERNEL32.@)
245 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
247 DWORD access
, sharing
;
249 TRACE("('%s',%04x)\n", path
, mode
);
250 FILE_ConvertOFMode( mode
, &access
, &sharing
);
251 return (HFILE
)CreateFileA( path
, access
, sharing
, NULL
, OPEN_EXISTING
, 0, 0 );
255 /***********************************************************************
256 * _lread (KERNEL32.@)
258 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
261 if (!ReadFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
))
267 /***********************************************************************
268 * _llseek (KERNEL32.@)
270 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
272 return SetFilePointer( (HANDLE
)hFile
, lOffset
, NULL
, nOrigin
);
276 /***********************************************************************
277 * _lwrite (KERNEL32.@)
279 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
281 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
285 /***********************************************************************
286 * FlushFileBuffers (KERNEL32.@)
288 BOOL WINAPI
FlushFileBuffers( HANDLE hFile
)
291 IO_STATUS_BLOCK ioblk
;
293 if (is_console_handle( hFile
))
295 /* this will fail (as expected) for an output handle */
296 /* FIXME: wait until FlushFileBuffers is moved to dll/kernel */
297 /* return FlushConsoleInputBuffer( hFile ); */
300 nts
= NtFlushBuffersFile( hFile
, &ioblk
);
301 if (nts
!= STATUS_SUCCESS
)
303 SetLastError( RtlNtStatusToDosError( nts
) );
311 /***********************************************************************
312 * GetFileSize (KERNEL32.@)
314 DWORD WINAPI
GetFileSize( HANDLE hFile
, LPDWORD filesizehigh
)
316 BY_HANDLE_FILE_INFORMATION info
;
317 if (!GetFileInformationByHandle( hFile
, &info
)) return -1;
318 if (filesizehigh
) *filesizehigh
= info
.nFileSizeHigh
;
319 return info
.nFileSizeLow
;
323 /***********************************************************************
324 * GetFileSizeEx (KERNEL32.@)
326 BOOL WINAPI
GetFileSizeEx( HANDLE hFile
, PLARGE_INTEGER lpFileSize
)
328 BY_HANDLE_FILE_INFORMATION info
;
332 SetLastError( ERROR_INVALID_PARAMETER
);
336 if (!GetFileInformationByHandle( hFile
, &info
))
341 lpFileSize
->u
.LowPart
= info
.nFileSizeLow
;
342 lpFileSize
->u
.HighPart
= info
.nFileSizeHigh
;
348 /**************************************************************************
349 * LockFile (KERNEL32.@)
351 BOOL WINAPI
LockFile( HANDLE hFile
, DWORD offset_low
, DWORD offset_high
,
352 DWORD count_low
, DWORD count_high
)
355 LARGE_INTEGER count
, offset
;
357 TRACE( "%p %lx%08lx %lx%08lx\n",
358 hFile
, offset_high
, offset_low
, count_high
, count_low
);
360 count
.u
.LowPart
= count_low
;
361 count
.u
.HighPart
= count_high
;
362 offset
.u
.LowPart
= offset_low
;
363 offset
.u
.HighPart
= offset_high
;
365 status
= NtLockFile( hFile
, 0, NULL
, NULL
,
366 NULL
, &offset
, &count
, NULL
, TRUE
, TRUE
);
368 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
373 /**************************************************************************
374 * LockFileEx [KERNEL32.@]
376 * Locks a byte range within an open file for shared or exclusive access.
383 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
385 BOOL WINAPI
LockFileEx( HANDLE hFile
, DWORD flags
, DWORD reserved
,
386 DWORD count_low
, DWORD count_high
, LPOVERLAPPED overlapped
)
389 LARGE_INTEGER count
, offset
;
393 SetLastError( ERROR_INVALID_PARAMETER
);
397 TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
398 hFile
, overlapped
->OffsetHigh
, overlapped
->Offset
,
399 count_high
, count_low
, flags
);
401 count
.u
.LowPart
= count_low
;
402 count
.u
.HighPart
= count_high
;
403 offset
.u
.LowPart
= overlapped
->Offset
;
404 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
406 status
= NtLockFile( hFile
, overlapped
->hEvent
, NULL
, NULL
,
407 NULL
, &offset
, &count
, NULL
,
408 flags
& LOCKFILE_FAIL_IMMEDIATELY
,
409 flags
& LOCKFILE_EXCLUSIVE_LOCK
);
411 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
416 /**************************************************************************
417 * UnlockFile (KERNEL32.@)
419 BOOL WINAPI
UnlockFile( HANDLE hFile
, DWORD offset_low
, DWORD offset_high
,
420 DWORD count_low
, DWORD count_high
)
423 LARGE_INTEGER count
, offset
;
425 count
.u
.LowPart
= count_low
;
426 count
.u
.HighPart
= count_high
;
427 offset
.u
.LowPart
= offset_low
;
428 offset
.u
.HighPart
= offset_high
;
430 status
= NtUnlockFile( hFile
, NULL
, &offset
, &count
, NULL
);
431 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
436 /**************************************************************************
437 * UnlockFileEx (KERNEL32.@)
439 BOOL WINAPI
UnlockFileEx( HANDLE hFile
, DWORD reserved
, DWORD count_low
, DWORD count_high
,
440 LPOVERLAPPED overlapped
)
444 SetLastError( ERROR_INVALID_PARAMETER
);
447 if (overlapped
->hEvent
) FIXME("Unimplemented overlapped operation\n");
449 return UnlockFile( hFile
, overlapped
->Offset
, overlapped
->OffsetHigh
, count_low
, count_high
);
453 /***********************************************************************
454 * Win32HandleToDosFileHandle (KERNEL32.21)
456 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
457 * longer valid after this function (even on failure).
459 * Note: this is not exactly right, since on Win95 the Win32 handles
460 * are on top of DOS handles and we do it the other way
461 * around. Should be good enough though.
463 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
467 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
470 FILE_InitProcessDosHandles();
471 for (i
= 0; i
< DOS_TABLE_SIZE
; i
++)
474 dos_handles
[i
] = handle
;
475 TRACE("Got %d for h32 %p\n", i
, handle
);
478 CloseHandle( handle
);
479 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
484 /***********************************************************************
485 * DosFileHandleToWin32Handle (KERNEL32.20)
487 * Return the Win32 handle for a DOS handle.
489 * Note: this is not exactly right, since on Win95 the Win32 handles
490 * are on top of DOS handles and we do it the other way
491 * around. Should be good enough though.
493 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
495 HFILE16 hfile
= (HFILE16
)handle
;
496 if (hfile
< 5) FILE_InitProcessDosHandles();
497 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
499 SetLastError( ERROR_INVALID_HANDLE
);
500 return INVALID_HANDLE_VALUE
;
502 return dos_handles
[hfile
];
506 /***********************************************************************
507 * DisposeLZ32Handle (KERNEL32.22)
509 * Note: this is not entirely correct, we should only close the
510 * 32-bit handle and not the 16-bit one, but we cannot do
511 * this because of the way our DOS handles are implemented.
512 * It shouldn't break anything though.
514 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
518 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
520 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
521 if (dos_handles
[i
] == handle
)
524 CloseHandle( handle
);
529 /**************************************************************************
530 * Operations on file names *
531 **************************************************************************/
533 /**************************************************************************
534 * ReplaceFileW (KERNEL32.@)
535 * ReplaceFile (KERNEL32.@)
537 BOOL WINAPI
ReplaceFileW(LPCWSTR lpReplacedFileName
,LPCWSTR lpReplacementFileName
,
538 LPCWSTR lpBackupFileName
, DWORD dwReplaceFlags
,
539 LPVOID lpExclude
, LPVOID lpReserved
)
541 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName
),debugstr_w(lpReplacementFileName
),
542 debugstr_w(lpBackupFileName
),dwReplaceFlags
,lpExclude
,lpReserved
);
543 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT
);
548 /**************************************************************************
549 * ReplaceFileA (KERNEL32.@)
551 BOOL WINAPI
ReplaceFileA(LPCSTR lpReplacedFileName
,LPCSTR lpReplacementFileName
,
552 LPCSTR lpBackupFileName
, DWORD dwReplaceFlags
,
553 LPVOID lpExclude
, LPVOID lpReserved
)
555 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName
,lpReplacementFileName
,
556 lpBackupFileName
,dwReplaceFlags
,lpExclude
,lpReserved
);
557 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT
);