Unicodify some comm functions.
[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 )) return -1;
262     return result;
263 }
264
265
266 /***********************************************************************
267  *           _llseek   (KERNEL32.@)
268  */
269 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
270 {
271     return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
272 }
273
274
275 /***********************************************************************
276  *           _lwrite   (KERNEL32.@)
277  */
278 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
279 {
280     return (UINT)_hwrite( hFile, buffer, (LONG)count );
281 }
282
283
284 /***********************************************************************
285  *           FlushFileBuffers   (KERNEL32.@)
286  */
287 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
288 {
289     NTSTATUS            nts;
290     IO_STATUS_BLOCK     ioblk;
291
292     if (is_console_handle( hFile ))
293     {
294         /* this will fail (as expected) for an output handle */
295         /* FIXME: wait until FlushFileBuffers is moved to dll/kernel */
296         /* return FlushConsoleInputBuffer( hFile ); */
297         return TRUE;
298     }
299     nts = NtFlushBuffersFile( hFile, &ioblk );
300     if (nts != STATUS_SUCCESS)
301     {
302         SetLastError( RtlNtStatusToDosError( nts ) );
303         return FALSE;
304     }
305
306     return TRUE;
307 }
308
309
310 /***********************************************************************
311  *           GetFileSize   (KERNEL32.@)
312  */
313 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
314 {
315     BY_HANDLE_FILE_INFORMATION info;
316     if (!GetFileInformationByHandle( hFile, &info )) return -1;
317     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
318     return info.nFileSizeLow;
319 }
320
321
322 /***********************************************************************
323  *           GetFileSizeEx   (KERNEL32.@)
324  */
325 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
326 {
327     BY_HANDLE_FILE_INFORMATION info;
328
329     if (!lpFileSize)
330     {
331         SetLastError( ERROR_INVALID_PARAMETER );
332         return FALSE;
333     }
334
335     if (!GetFileInformationByHandle( hFile, &info ))
336     {
337         return FALSE;
338     }
339
340     lpFileSize->s.LowPart = info.nFileSizeLow;
341     lpFileSize->s.HighPart = info.nFileSizeHigh;
342
343     return TRUE;
344 }
345
346
347 /**************************************************************************
348  *           LockFile   (KERNEL32.@)
349  */
350 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
351                       DWORD count_low, DWORD count_high )
352 {
353     NTSTATUS            status;
354     LARGE_INTEGER       count, offset;
355
356     TRACE( "%p %lx%08lx %lx%08lx\n", 
357            hFile, offset_high, offset_low, count_high, count_low );
358
359     count.s.LowPart = count_low;
360     count.s.HighPart = count_high;
361     offset.s.LowPart = offset_low;
362     offset.s.HighPart = offset_high;
363
364     status = NtLockFile( hFile, 0, NULL, NULL, 
365                          NULL, &offset, &count, NULL, TRUE, TRUE );
366     
367     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
368     return !status;
369 }
370
371
372 /**************************************************************************
373  * LockFileEx [KERNEL32.@]
374  *
375  * Locks a byte range within an open file for shared or exclusive access.
376  *
377  * RETURNS
378  *   success: TRUE
379  *   failure: FALSE
380  *
381  * NOTES
382  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
383  */
384 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
385                         DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
386 {
387     NTSTATUS status;
388     LARGE_INTEGER count, offset;
389
390     if (reserved)
391     {
392         SetLastError( ERROR_INVALID_PARAMETER );
393         return FALSE;
394     }
395
396     TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
397            hFile, overlapped->OffsetHigh, overlapped->Offset, 
398            count_high, count_low, flags );
399
400     count.s.LowPart = count_low;
401     count.s.HighPart = count_high;
402     offset.s.LowPart = overlapped->Offset;
403     offset.s.HighPart = overlapped->OffsetHigh;
404
405     status = NtLockFile( hFile, overlapped->hEvent, NULL, NULL, 
406                          NULL, &offset, &count, NULL, 
407                          flags & LOCKFILE_FAIL_IMMEDIATELY,
408                          flags & LOCKFILE_EXCLUSIVE_LOCK );
409     
410     if (status) SetLastError( RtlNtStatusToDosError(status) );
411     return !status;
412 }
413
414
415 /**************************************************************************
416  *           UnlockFile   (KERNEL32.@)
417  */
418 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
419                         DWORD count_low, DWORD count_high )
420 {
421     NTSTATUS    status;
422     LARGE_INTEGER count, offset;
423
424     count.s.LowPart = count_low;
425     count.s.HighPart = count_high;
426     offset.s.LowPart = offset_low;
427     offset.s.HighPart = offset_high;
428
429     status = NtUnlockFile( hFile, NULL, &offset, &count, NULL);
430     if (status) SetLastError( RtlNtStatusToDosError(status) );
431     return !status;
432 }
433
434
435 /**************************************************************************
436  *           UnlockFileEx   (KERNEL32.@)
437  */
438 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
439                           LPOVERLAPPED overlapped )
440 {
441     if (reserved)
442     {
443         SetLastError( ERROR_INVALID_PARAMETER );
444         return FALSE;
445     }
446     if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n");
447
448     return UnlockFile( hFile, overlapped->Offset, overlapped->OffsetHigh, count_low, count_high );
449 }
450
451
452 /***********************************************************************
453  *           Win32HandleToDosFileHandle   (KERNEL32.21)
454  *
455  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
456  * longer valid after this function (even on failure).
457  *
458  * Note: this is not exactly right, since on Win95 the Win32 handles
459  *       are on top of DOS handles and we do it the other way
460  *       around. Should be good enough though.
461  */
462 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
463 {
464     int i;
465
466     if (!handle || (handle == INVALID_HANDLE_VALUE))
467         return HFILE_ERROR;
468
469     FILE_InitProcessDosHandles();
470     for (i = 0; i < DOS_TABLE_SIZE; i++)
471         if (!dos_handles[i])
472         {
473             dos_handles[i] = handle;
474             TRACE("Got %d for h32 %p\n", i, handle );
475             return (HFILE)i;
476         }
477     CloseHandle( handle );
478     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
479     return HFILE_ERROR;
480 }
481
482
483 /***********************************************************************
484  *           DosFileHandleToWin32Handle   (KERNEL32.20)
485  *
486  * Return the Win32 handle for a DOS handle.
487  *
488  * Note: this is not exactly right, since on Win95 the Win32 handles
489  *       are on top of DOS handles and we do it the other way
490  *       around. Should be good enough though.
491  */
492 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
493 {
494     HFILE16 hfile = (HFILE16)handle;
495     if (hfile < 5) FILE_InitProcessDosHandles();
496     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
497     {
498         SetLastError( ERROR_INVALID_HANDLE );
499         return INVALID_HANDLE_VALUE;
500     }
501     return dos_handles[hfile];
502 }
503
504
505 /***********************************************************************
506  *           DisposeLZ32Handle   (KERNEL32.22)
507  *
508  * Note: this is not entirely correct, we should only close the
509  *       32-bit handle and not the 16-bit one, but we cannot do
510  *       this because of the way our DOS handles are implemented.
511  *       It shouldn't break anything though.
512  */
513 void WINAPI DisposeLZ32Handle( HANDLE handle )
514 {
515     int i;
516
517     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
518
519     for (i = 5; i < DOS_TABLE_SIZE; i++)
520         if (dos_handles[i] == handle)
521         {
522             dos_handles[i] = 0;
523             CloseHandle( handle );
524             break;
525         }
526 }
527
528 /**************************************************************************
529  *                      Operations on file names                          *
530  **************************************************************************/
531
532 /**************************************************************************
533  *           ReplaceFileW   (KERNEL32.@)
534  *           ReplaceFile    (KERNEL32.@)
535  */
536 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
537                          LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
538                          LPVOID lpExclude, LPVOID lpReserved)
539 {
540     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
541                                           debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
542     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
543     return FALSE;
544 }
545
546
547 /**************************************************************************
548  *           ReplaceFileA (KERNEL32.@)
549  */
550 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
551                          LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
552                          LPVOID lpExclude, LPVOID lpReserved)
553 {
554     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
555                                           lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
556     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
557     return FALSE;
558 }