Fixed regression in loading of builtin apps from the system dir when
[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 "kernel_private.h"
41
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
44 #include "async.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(file);
47
48 /**************************************************************************
49  *                      Operations on file handles                        *
50  **************************************************************************/
51
52 /***********************************************************************
53  *              GetOverlappedResult     (KERNEL32.@)
54  *
55  * Check the result of an Asynchronous data transfer from a file.
56  *
57  * Parameters
58  *   HANDLE hFile                 [in] handle of file to check on
59  *   LPOVERLAPPED lpOverlapped    [in/out] pointer to overlapped
60  *   LPDWORD lpTransferred        [in/out] number of bytes transferred
61  *   BOOL bWait                   [in] wait for the transfer to complete ?
62  *
63  * RETURNS
64  *   TRUE on success
65  *   FALSE on failure
66  *
67  *  If successful (and relevant) lpTransferred will hold the number of
68  *   bytes transferred during the async operation.
69  *
70  * BUGS
71  *
72  * Currently only works for WaitCommEvent, ReadFile, WriteFile
73  *   with communications ports.
74  *
75  */
76 BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
77                                 LPDWORD lpTransferred, BOOL bWait)
78 {
79     DWORD r;
80
81     TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
82
83     if (lpOverlapped==NULL)
84     {
85         ERR("lpOverlapped was null\n");
86         return FALSE;
87     }
88     if (!lpOverlapped->hEvent)
89     {
90         ERR("lpOverlapped->hEvent was null\n");
91         return FALSE;
92     }
93
94     if ( bWait )
95     {
96         do {
97             TRACE("waiting on %p\n",lpOverlapped);
98             r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
99             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
100         } while (r==STATUS_USER_APC);
101     }
102     else if ( lpOverlapped->Internal == STATUS_PENDING )
103     {
104         /* Wait in order to give APCs a chance to run. */
105         /* This is cheating, so we must set the event again in case of success -
106            it may be a non-manual reset event. */
107         do {
108             TRACE("waiting on %p\n",lpOverlapped);
109             r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
110             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
111         } while (r==STATUS_USER_APC);
112         if ( r == WAIT_OBJECT_0 )
113             NtSetEvent ( lpOverlapped->hEvent, NULL );
114     }
115
116     if(lpTransferred)
117         *lpTransferred = lpOverlapped->InternalHigh;
118
119     switch ( lpOverlapped->Internal )
120     {
121     case STATUS_SUCCESS:
122         return TRUE;
123     case STATUS_PENDING:
124         SetLastError ( ERROR_IO_INCOMPLETE );
125         if ( bWait ) ERR ("PENDING status after waiting!\n");
126         return FALSE;
127     default:
128         SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
129         return FALSE;
130     }
131 }
132
133 /***********************************************************************
134  *             CancelIo                   (KERNEL32.@)
135  */
136 BOOL WINAPI CancelIo(HANDLE handle)
137 {
138     async_private *ovp,*t;
139
140     TRACE("handle = %p\n",handle);
141
142     for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
143     {
144         t = ovp->next;
145         if ( ovp->handle == handle )
146              cancel_async ( ovp );
147     }
148     SleepEx(1,TRUE);
149     return TRUE;
150 }
151
152 /***********************************************************************
153  *           _hread   (KERNEL32.@)
154  */
155 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
156 {
157     return _lread( hFile, buffer, count );
158 }
159
160
161 /***********************************************************************
162  *           _hwrite   (KERNEL32.@)
163  *
164  *      experimentation yields that _lwrite:
165  *              o truncates the file at the current position with
166  *                a 0 len write
167  *              o returns 0 on a 0 length write
168  *              o works with console handles
169  *
170  */
171 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
172 {
173     DWORD result;
174
175     TRACE("%d %p %ld\n", handle, buffer, count );
176
177     if (!count)
178     {
179         /* Expand or truncate at current position */
180         if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
181         return 0;
182     }
183     if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
184         return HFILE_ERROR;
185     return result;
186 }
187
188
189 /***********************************************************************
190  *           _lclose   (KERNEL32.@)
191  */
192 HFILE WINAPI _lclose( HFILE hFile )
193 {
194     TRACE("handle %d\n", hFile );
195     return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
196 }
197
198
199 /***********************************************************************
200  *           _lcreat   (KERNEL32.@)
201  */
202 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
203 {
204     /* Mask off all flags not explicitly allowed by the doc */
205     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
206     TRACE("%s %02x\n", path, attr );
207     return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
208                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
209                                CREATE_ALWAYS, attr, 0 );
210 }
211
212
213 /***********************************************************************
214  *           _lopen   (KERNEL32.@)
215  */
216 HFILE WINAPI _lopen( LPCSTR path, INT mode )
217 {
218     DWORD access, sharing;
219
220     TRACE("('%s',%04x)\n", path, mode );
221     FILE_ConvertOFMode( mode, &access, &sharing );
222     return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
223 }
224
225
226 /***********************************************************************
227  *           _lread   (KERNEL32.@)
228  */
229 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
230 {
231     DWORD result;
232     if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
233     return result;
234 }
235
236
237 /***********************************************************************
238  *           _llseek   (KERNEL32.@)
239  */
240 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
241 {
242     return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
243 }
244
245
246 /***********************************************************************
247  *           _lwrite   (KERNEL32.@)
248  */
249 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
250 {
251     return (UINT)_hwrite( hFile, buffer, (LONG)count );
252 }
253
254
255 /***********************************************************************
256  *           FlushFileBuffers   (KERNEL32.@)
257  */
258 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
259 {
260     NTSTATUS            nts;
261     IO_STATUS_BLOCK     ioblk;
262
263     if (is_console_handle( hFile ))
264     {
265         /* this will fail (as expected) for an output handle */
266         /* FIXME: wait until FlushFileBuffers is moved to dll/kernel */
267         /* return FlushConsoleInputBuffer( hFile ); */
268         return TRUE;
269     }
270     nts = NtFlushBuffersFile( hFile, &ioblk );
271     if (nts != STATUS_SUCCESS)
272     {
273         SetLastError( RtlNtStatusToDosError( nts ) );
274         return FALSE;
275     }
276
277     return TRUE;
278 }
279
280
281 /***********************************************************************
282  *           GetFileSize   (KERNEL32.@)
283  */
284 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
285 {
286     BY_HANDLE_FILE_INFORMATION info;
287     if (!GetFileInformationByHandle( hFile, &info )) return -1;
288     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
289     return info.nFileSizeLow;
290 }
291
292
293 /***********************************************************************
294  *           GetFileSizeEx   (KERNEL32.@)
295  */
296 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
297 {
298     BY_HANDLE_FILE_INFORMATION info;
299
300     if (!lpFileSize)
301     {
302         SetLastError( ERROR_INVALID_PARAMETER );
303         return FALSE;
304     }
305
306     if (!GetFileInformationByHandle( hFile, &info ))
307     {
308         return FALSE;
309     }
310
311     lpFileSize->s.LowPart = info.nFileSizeLow;
312     lpFileSize->s.HighPart = info.nFileSizeHigh;
313
314     return TRUE;
315 }
316
317
318 /**************************************************************************
319  *           LockFile   (KERNEL32.@)
320  */
321 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
322                       DWORD count_low, DWORD count_high )
323 {
324     NTSTATUS            status;
325     LARGE_INTEGER       count, offset;
326
327     TRACE( "%p %lx%08lx %lx%08lx\n", 
328            hFile, offset_high, offset_low, count_high, count_low );
329
330     count.s.LowPart = count_low;
331     count.s.HighPart = count_high;
332     offset.s.LowPart = offset_low;
333     offset.s.HighPart = offset_high;
334
335     status = NtLockFile( hFile, 0, NULL, NULL, 
336                          NULL, &offset, &count, NULL, TRUE, TRUE );
337     
338     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
339     return !status;
340 }
341
342
343 /**************************************************************************
344  * LockFileEx [KERNEL32.@]
345  *
346  * Locks a byte range within an open file for shared or exclusive access.
347  *
348  * RETURNS
349  *   success: TRUE
350  *   failure: FALSE
351  *
352  * NOTES
353  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
354  */
355 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
356                         DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
357 {
358     NTSTATUS status;
359     LARGE_INTEGER count, offset;
360
361     if (reserved)
362     {
363         SetLastError( ERROR_INVALID_PARAMETER );
364         return FALSE;
365     }
366
367     TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
368            hFile, overlapped->OffsetHigh, overlapped->Offset, 
369            count_high, count_low, flags );
370
371     count.s.LowPart = count_low;
372     count.s.HighPart = count_high;
373     offset.s.LowPart = overlapped->Offset;
374     offset.s.HighPart = overlapped->OffsetHigh;
375
376     status = NtLockFile( hFile, overlapped->hEvent, NULL, NULL, 
377                          NULL, &offset, &count, NULL, 
378                          flags & LOCKFILE_FAIL_IMMEDIATELY,
379                          flags & LOCKFILE_EXCLUSIVE_LOCK );
380     
381     if (status) SetLastError( RtlNtStatusToDosError(status) );
382     return !status;
383 }
384
385
386 /**************************************************************************
387  *           UnlockFile   (KERNEL32.@)
388  */
389 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
390                         DWORD count_low, DWORD count_high )
391 {
392     NTSTATUS    status;
393     LARGE_INTEGER count, offset;
394
395     count.s.LowPart = count_low;
396     count.s.HighPart = count_high;
397     offset.s.LowPart = offset_low;
398     offset.s.HighPart = offset_high;
399
400     status = NtUnlockFile( hFile, NULL, &offset, &count, NULL);
401     if (status) SetLastError( RtlNtStatusToDosError(status) );
402     return !status;
403 }
404
405
406 /**************************************************************************
407  *           UnlockFileEx   (KERNEL32.@)
408  */
409 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
410                           LPOVERLAPPED overlapped )
411 {
412     if (reserved)
413     {
414         SetLastError( ERROR_INVALID_PARAMETER );
415         return FALSE;
416     }
417     if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n");
418
419     return UnlockFile( hFile, overlapped->Offset, overlapped->OffsetHigh, count_low, count_high );
420 }
421
422 /**************************************************************************
423  *                      Operations on file names                          *
424  **************************************************************************/
425
426 /**************************************************************************
427  *           ReplaceFileW   (KERNEL32.@)
428  *           ReplaceFile    (KERNEL32.@)
429  */
430 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
431                          LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
432                          LPVOID lpExclude, LPVOID lpReserved)
433 {
434     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
435                                           debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
436     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
437     return FALSE;
438 }
439
440
441 /**************************************************************************
442  *           ReplaceFileA (KERNEL32.@)
443  */
444 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
445                          LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
446                          LPVOID lpExclude, LPVOID lpReserved)
447 {
448     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
449                                           lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
450     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
451     return FALSE;
452 }