Return HFILE_ERROR instead of -1 in _lread.
[wine/multimedia.git] / dlls / kernel / file.c
blob9cd924b30f751cfbb43319897f6cacea3ccc10fb
1 /*
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
21 * TODO:
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33 #include "winerror.h"
34 #include "ntstatus.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winternl.h"
39 #include "wincon.h"
40 #include "wine/winbase16.h"
41 #include "kernel_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "async.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;
67 init_done = TRUE;
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.
86 * Parameters
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 ?
92 * RETURNS
93 * TRUE on success
94 * FALSE on failure
96 * If successful (and relevant) lpTransferred will hold the number of
97 * bytes transferred during the async operation.
99 * BUGS
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)
108 DWORD r;
110 TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
112 if (lpOverlapped==NULL)
114 ERR("lpOverlapped was null\n");
115 return FALSE;
117 if (!lpOverlapped->hEvent)
119 ERR("lpOverlapped->hEvent was null\n");
120 return FALSE;
123 if ( bWait )
125 do {
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. */
136 do {
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 );
145 if(lpTransferred)
146 *lpTransferred = lpOverlapped->InternalHigh;
148 switch ( lpOverlapped->Internal )
150 case STATUS_SUCCESS:
151 return TRUE;
152 case STATUS_PENDING:
153 SetLastError ( ERROR_IO_INCOMPLETE );
154 if ( bWait ) ERR ("PENDING status after waiting!\n");
155 return FALSE;
156 default:
157 SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
158 return FALSE;
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)
173 t = ovp->next;
174 if ( ovp->handle == handle )
175 cancel_async ( ovp );
177 SleepEx(1,TRUE);
178 return TRUE;
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
195 * a 0 len write
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 )
202 DWORD result;
204 TRACE("%d %p %ld\n", handle, buffer, count );
206 if (!count)
208 /* Expand or truncate at current position */
209 if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
210 return 0;
212 if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
213 return HFILE_ERROR;
214 return result;
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 )
260 DWORD result;
261 if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL ))
262 return HFILE_ERROR;
263 return result;
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 )
290 NTSTATUS nts;
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 ); */
298 return TRUE;
300 nts = NtFlushBuffersFile( hFile, &ioblk );
301 if (nts != STATUS_SUCCESS)
303 SetLastError( RtlNtStatusToDosError( nts ) );
304 return FALSE;
307 return TRUE;
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;
330 if (!lpFileSize)
332 SetLastError( ERROR_INVALID_PARAMETER );
333 return FALSE;
336 if (!GetFileInformationByHandle( hFile, &info ))
338 return FALSE;
341 lpFileSize->s.LowPart = info.nFileSizeLow;
342 lpFileSize->s.HighPart = info.nFileSizeHigh;
344 return TRUE;
348 /**************************************************************************
349 * LockFile (KERNEL32.@)
351 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
352 DWORD count_low, DWORD count_high )
354 NTSTATUS status;
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.s.LowPart = count_low;
361 count.s.HighPart = count_high;
362 offset.s.LowPart = offset_low;
363 offset.s.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) );
369 return !status;
373 /**************************************************************************
374 * LockFileEx [KERNEL32.@]
376 * Locks a byte range within an open file for shared or exclusive access.
378 * RETURNS
379 * success: TRUE
380 * failure: FALSE
382 * NOTES
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 )
388 NTSTATUS status;
389 LARGE_INTEGER count, offset;
391 if (reserved)
393 SetLastError( ERROR_INVALID_PARAMETER );
394 return FALSE;
397 TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
398 hFile, overlapped->OffsetHigh, overlapped->Offset,
399 count_high, count_low, flags );
401 count.s.LowPart = count_low;
402 count.s.HighPart = count_high;
403 offset.s.LowPart = overlapped->Offset;
404 offset.s.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) );
412 return !status;
416 /**************************************************************************
417 * UnlockFile (KERNEL32.@)
419 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
420 DWORD count_low, DWORD count_high )
422 NTSTATUS status;
423 LARGE_INTEGER count, offset;
425 count.s.LowPart = count_low;
426 count.s.HighPart = count_high;
427 offset.s.LowPart = offset_low;
428 offset.s.HighPart = offset_high;
430 status = NtUnlockFile( hFile, NULL, &offset, &count, NULL);
431 if (status) SetLastError( RtlNtStatusToDosError(status) );
432 return !status;
436 /**************************************************************************
437 * UnlockFileEx (KERNEL32.@)
439 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
440 LPOVERLAPPED overlapped )
442 if (reserved)
444 SetLastError( ERROR_INVALID_PARAMETER );
445 return FALSE;
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 )
465 int i;
467 if (!handle || (handle == INVALID_HANDLE_VALUE))
468 return HFILE_ERROR;
470 FILE_InitProcessDosHandles();
471 for (i = 0; i < DOS_TABLE_SIZE; i++)
472 if (!dos_handles[i])
474 dos_handles[i] = handle;
475 TRACE("Got %d for h32 %p\n", i, handle );
476 return (HFILE)i;
478 CloseHandle( handle );
479 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
480 return HFILE_ERROR;
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 )
516 int i;
518 if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
520 for (i = 5; i < DOS_TABLE_SIZE; i++)
521 if (dos_handles[i] == handle)
523 dos_handles[i] = 0;
524 CloseHandle( handle );
525 break;
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);
544 return FALSE;
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);
558 return FALSE;