Changed the CreateDC driver entry point to use an HDC instead of a DC
[wine] / dlls / kernel / file.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 John Burton
5  * Copyright 1996 Alexandre Julliard
6  *
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.
11  *
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.
16  *
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
20  *
21  * TODO:
22  *    Fix the CopyFileEx methods to implement the "extended" functionality.
23  *    Right now, they simply call the CopyFile method.
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <stdarg.h>
30
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"
42
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "async.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(file);
48
49 HANDLE dos_handles[DOS_TABLE_SIZE];
50
51 /**************************************************************************
52  *                      Operations on file handles                        *
53  **************************************************************************/
54
55 /***********************************************************************
56  *           FILE_InitProcessDosHandles
57  *
58  * Allocates the default DOS handles for a process. Called either by
59  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
60  */
61 static void FILE_InitProcessDosHandles( void )
62 {
63     static BOOL init_done /* = FALSE */;
64     HANDLE cp = GetCurrentProcess();
65
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);
78 }
79
80
81 /***********************************************************************
82  *              GetOverlappedResult     (KERNEL32.@)
83  *
84  * Check the result of an Asynchronous data transfer from a file.
85  *
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 ?
91  *
92  * RETURNS
93  *   TRUE on success
94  *   FALSE on failure
95  *
96  *  If successful (and relevant) lpTransferred will hold the number of
97  *   bytes transferred during the async operation.
98  *
99  * BUGS
100  *
101  * Currently only works for WaitCommEvent, ReadFile, WriteFile
102  *   with communications ports.
103  *
104  */
105 BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
106                                 LPDWORD lpTransferred, BOOL bWait)
107 {
108     DWORD r;
109
110     TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
111
112     if (lpOverlapped==NULL)
113     {
114         ERR("lpOverlapped was null\n");
115         return FALSE;
116     }
117     if (!lpOverlapped->hEvent)
118     {
119         ERR("lpOverlapped->hEvent was null\n");
120         return FALSE;
121     }
122
123     if ( bWait )
124     {
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);
130     }
131     else if ( lpOverlapped->Internal == STATUS_PENDING )
132     {
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 );
143     }
144
145     if(lpTransferred)
146         *lpTransferred = lpOverlapped->InternalHigh;
147
148     switch ( lpOverlapped->Internal )
149     {
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;
159     }
160 }
161
162 /***********************************************************************
163  *             CancelIo                   (KERNEL32.@)
164  */
165 BOOL WINAPI CancelIo(HANDLE handle)
166 {
167     async_private *ovp,*t;
168
169     TRACE("handle = %p\n",handle);
170
171     for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
172     {
173         t = ovp->next;
174         if ( ovp->handle == handle )
175              cancel_async ( ovp );
176     }
177     SleepEx(1,TRUE);
178     return TRUE;
179 }
180
181 /***********************************************************************
182  *           _hread   (KERNEL32.@)
183  */
184 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
185 {
186     return _lread( hFile, buffer, count );
187 }
188
189
190 /***********************************************************************
191  *           _hwrite   (KERNEL32.@)
192  *
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
198  *
199  */
200 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
201 {
202     DWORD result;
203
204     TRACE("%d %p %ld\n", handle, buffer, count );
205
206     if (!count)
207     {
208         /* Expand or truncate at current position */
209         if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
210         return 0;
211     }
212     if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
213         return HFILE_ERROR;
214     return result;
215 }
216
217
218 /***********************************************************************
219  *           _lclose   (KERNEL32.@)
220  */
221 HFILE WINAPI _lclose( HFILE hFile )
222 {
223     TRACE("handle %d\n", hFile );
224     return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
225 }
226
227
228 /***********************************************************************
229  *           _lcreat   (KERNEL32.@)
230  */
231 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
232 {
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 );
239 }
240
241
242 /***********************************************************************
243  *           _lopen   (KERNEL32.@)
244  */
245 HFILE WINAPI _lopen( LPCSTR path, INT mode )
246 {
247     DWORD access, sharing;
248
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 );
252 }
253
254
255 /***********************************************************************
256  *           _lread   (KERNEL32.@)
257  */
258 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
259 {
260     DWORD result;
261     if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL ))
262         return HFILE_ERROR;
263     return result;
264 }
265
266
267 /***********************************************************************
268  *           _llseek   (KERNEL32.@)
269  */
270 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
271 {
272     return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
273 }
274
275
276 /***********************************************************************
277  *           _lwrite   (KERNEL32.@)
278  */
279 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
280 {
281     return (UINT)_hwrite( hFile, buffer, (LONG)count );
282 }
283
284
285 /***********************************************************************
286  *           FlushFileBuffers   (KERNEL32.@)
287  */
288 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
289 {
290     NTSTATUS            nts;
291     IO_STATUS_BLOCK     ioblk;
292
293     if (is_console_handle( hFile ))
294     {
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;
299     }
300     nts = NtFlushBuffersFile( hFile, &ioblk );
301     if (nts != STATUS_SUCCESS)
302     {
303         SetLastError( RtlNtStatusToDosError( nts ) );
304         return FALSE;
305     }
306
307     return TRUE;
308 }
309
310
311 /***********************************************************************
312  *           GetFileSize   (KERNEL32.@)
313  */
314 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
315 {
316     BY_HANDLE_FILE_INFORMATION info;
317     if (!GetFileInformationByHandle( hFile, &info )) return -1;
318     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
319     return info.nFileSizeLow;
320 }
321
322
323 /***********************************************************************
324  *           GetFileSizeEx   (KERNEL32.@)
325  */
326 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
327 {
328     BY_HANDLE_FILE_INFORMATION info;
329
330     if (!lpFileSize)
331     {
332         SetLastError( ERROR_INVALID_PARAMETER );
333         return FALSE;
334     }
335
336     if (!GetFileInformationByHandle( hFile, &info ))
337     {
338         return FALSE;
339     }
340
341     lpFileSize->u.LowPart = info.nFileSizeLow;
342     lpFileSize->u.HighPart = info.nFileSizeHigh;
343
344     return TRUE;
345 }
346
347
348 /**************************************************************************
349  *           LockFile   (KERNEL32.@)
350  */
351 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
352                       DWORD count_low, DWORD count_high )
353 {
354     NTSTATUS            status;
355     LARGE_INTEGER       count, offset;
356
357     TRACE( "%p %lx%08lx %lx%08lx\n", 
358            hFile, offset_high, offset_low, count_high, count_low );
359
360     count.u.LowPart = count_low;
361     count.u.HighPart = count_high;
362     offset.u.LowPart = offset_low;
363     offset.u.HighPart = offset_high;
364
365     status = NtLockFile( hFile, 0, NULL, NULL, 
366                          NULL, &offset, &count, NULL, TRUE, TRUE );
367     
368     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
369     return !status;
370 }
371
372
373 /**************************************************************************
374  * LockFileEx [KERNEL32.@]
375  *
376  * Locks a byte range within an open file for shared or exclusive access.
377  *
378  * RETURNS
379  *   success: TRUE
380  *   failure: FALSE
381  *
382  * NOTES
383  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
384  */
385 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
386                         DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
387 {
388     NTSTATUS status;
389     LARGE_INTEGER count, offset;
390
391     if (reserved)
392     {
393         SetLastError( ERROR_INVALID_PARAMETER );
394         return FALSE;
395     }
396
397     TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
398            hFile, overlapped->OffsetHigh, overlapped->Offset, 
399            count_high, count_low, flags );
400
401     count.u.LowPart = count_low;
402     count.u.HighPart = count_high;
403     offset.u.LowPart = overlapped->Offset;
404     offset.u.HighPart = overlapped->OffsetHigh;
405
406     status = NtLockFile( hFile, overlapped->hEvent, NULL, NULL, 
407                          NULL, &offset, &count, NULL, 
408                          flags & LOCKFILE_FAIL_IMMEDIATELY,
409                          flags & LOCKFILE_EXCLUSIVE_LOCK );
410     
411     if (status) SetLastError( RtlNtStatusToDosError(status) );
412     return !status;
413 }
414
415
416 /**************************************************************************
417  *           UnlockFile   (KERNEL32.@)
418  */
419 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
420                         DWORD count_low, DWORD count_high )
421 {
422     NTSTATUS    status;
423     LARGE_INTEGER count, offset;
424
425     count.u.LowPart = count_low;
426     count.u.HighPart = count_high;
427     offset.u.LowPart = offset_low;
428     offset.u.HighPart = offset_high;
429
430     status = NtUnlockFile( hFile, NULL, &offset, &count, NULL);
431     if (status) SetLastError( RtlNtStatusToDosError(status) );
432     return !status;
433 }
434
435
436 /**************************************************************************
437  *           UnlockFileEx   (KERNEL32.@)
438  */
439 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
440                           LPOVERLAPPED overlapped )
441 {
442     if (reserved)
443     {
444         SetLastError( ERROR_INVALID_PARAMETER );
445         return FALSE;
446     }
447     if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n");
448
449     return UnlockFile( hFile, overlapped->Offset, overlapped->OffsetHigh, count_low, count_high );
450 }
451
452
453 /***********************************************************************
454  *           Win32HandleToDosFileHandle   (KERNEL32.21)
455  *
456  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
457  * longer valid after this function (even on failure).
458  *
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.
462  */
463 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
464 {
465     int i;
466
467     if (!handle || (handle == INVALID_HANDLE_VALUE))
468         return HFILE_ERROR;
469
470     FILE_InitProcessDosHandles();
471     for (i = 0; i < DOS_TABLE_SIZE; i++)
472         if (!dos_handles[i])
473         {
474             dos_handles[i] = handle;
475             TRACE("Got %d for h32 %p\n", i, handle );
476             return (HFILE)i;
477         }
478     CloseHandle( handle );
479     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
480     return HFILE_ERROR;
481 }
482
483
484 /***********************************************************************
485  *           DosFileHandleToWin32Handle   (KERNEL32.20)
486  *
487  * Return the Win32 handle for a DOS handle.
488  *
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.
492  */
493 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
494 {
495     HFILE16 hfile = (HFILE16)handle;
496     if (hfile < 5) FILE_InitProcessDosHandles();
497     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
498     {
499         SetLastError( ERROR_INVALID_HANDLE );
500         return INVALID_HANDLE_VALUE;
501     }
502     return dos_handles[hfile];
503 }
504
505
506 /***********************************************************************
507  *           DisposeLZ32Handle   (KERNEL32.22)
508  *
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.
513  */
514 void WINAPI DisposeLZ32Handle( HANDLE handle )
515 {
516     int i;
517
518     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
519
520     for (i = 5; i < DOS_TABLE_SIZE; i++)
521         if (dos_handles[i] == handle)
522         {
523             dos_handles[i] = 0;
524             CloseHandle( handle );
525             break;
526         }
527 }
528
529 /**************************************************************************
530  *                      Operations on file names                          *
531  **************************************************************************/
532
533 /**************************************************************************
534  *           ReplaceFileW   (KERNEL32.@)
535  *           ReplaceFile    (KERNEL32.@)
536  */
537 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
538                          LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
539                          LPVOID lpExclude, LPVOID lpReserved)
540 {
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;
545 }
546
547
548 /**************************************************************************
549  *           ReplaceFileA (KERNEL32.@)
550  */
551 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
552                          LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
553                          LPVOID lpExclude, LPVOID lpReserved)
554 {
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;
559 }