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