~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/kernel32/file.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * File handling functions
  3  *
  4  * Copyright 1993 John Burton
  5  * Copyright 1996, 2004 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 20  */
 21 
 22 #include "config.h"
 23 #include "wine/port.h"
 24 
 25 #include <stdarg.h>
 26 #include <stdio.h>
 27 #include <errno.h>
 28 #ifdef HAVE_SYS_STAT_H
 29 # include <sys/stat.h>
 30 #endif
 31 
 32 #define NONAMELESSUNION
 33 #define NONAMELESSSTRUCT
 34 #include "winerror.h"
 35 #include "ntstatus.h"
 36 #define WIN32_NO_STATUS
 37 #include "windef.h"
 38 #include "winbase.h"
 39 #include "winternl.h"
 40 #include "winioctl.h"
 41 #include "wincon.h"
 42 #include "wine/winbase16.h"
 43 #include "kernel_private.h"
 44 
 45 #include "wine/exception.h"
 46 #include "wine/unicode.h"
 47 #include "wine/debug.h"
 48 
 49 WINE_DEFAULT_DEBUG_CHANNEL(file);
 50 
 51 HANDLE dos_handles[DOS_TABLE_SIZE];
 52 
 53 /* info structure for FindFirstFile handle */
 54 typedef struct
 55 {
 56     DWORD             magic;       /* magic number */
 57     HANDLE            handle;      /* handle to directory */
 58     CRITICAL_SECTION  cs;          /* crit section protecting this structure */
 59     FINDEX_SEARCH_OPS search_op;   /* Flags passed to FindFirst.  */
 60     UNICODE_STRING    mask;        /* file mask */
 61     UNICODE_STRING    path;        /* NT path used to open the directory */
 62     BOOL              is_root;     /* is directory the root of the drive? */
 63     UINT              data_pos;    /* current position in dir data */
 64     UINT              data_len;    /* length of dir data */
 65     BYTE              data[8192];  /* directory data */
 66 } FIND_FIRST_INFO;
 67 
 68 #define FIND_FIRST_MAGIC  0xc0ffee11
 69 
 70 static BOOL oem_file_apis;
 71 
 72 static const WCHAR wildcardsW[] = { '*','?',0 };
 73 
 74 /***********************************************************************
 75  *              create_file_OF
 76  *
 77  * Wrapper for CreateFile that takes OF_* mode flags.
 78  */
 79 static HANDLE create_file_OF( LPCSTR path, INT mode )
 80 {
 81     DWORD access, sharing, creation;
 82 
 83     if (mode & OF_CREATE)
 84     {
 85         creation = CREATE_ALWAYS;
 86         access = GENERIC_READ | GENERIC_WRITE;
 87     }
 88     else
 89     {
 90         creation = OPEN_EXISTING;
 91         switch(mode & 0x03)
 92         {
 93         case OF_READ:      access = GENERIC_READ; break;
 94         case OF_WRITE:     access = GENERIC_WRITE; break;
 95         case OF_READWRITE: access = GENERIC_READ | GENERIC_WRITE; break;
 96         default:           access = 0; break;
 97         }
 98     }
 99 
100     switch(mode & 0x70)
101     {
102     case OF_SHARE_EXCLUSIVE:  sharing = 0; break;
103     case OF_SHARE_DENY_WRITE: sharing = FILE_SHARE_READ; break;
104     case OF_SHARE_DENY_READ:  sharing = FILE_SHARE_WRITE; break;
105     case OF_SHARE_DENY_NONE:
106     case OF_SHARE_COMPAT:
107     default:                  sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
108     }
109     return CreateFileA( path, access, sharing, NULL, creation, FILE_ATTRIBUTE_NORMAL, 0 );
110 }
111 
112 
113 /***********************************************************************
114  *              check_dir_symlink
115  *
116  * Check if a dir symlink should be returned by FindNextFile.
117  */
118 static BOOL check_dir_symlink( FIND_FIRST_INFO *info, const FILE_BOTH_DIR_INFORMATION *file_info )
119 {
120     UNICODE_STRING str;
121     ANSI_STRING unix_name;
122     struct stat st, parent_st;
123     BOOL ret = TRUE;
124     DWORD len;
125 
126     str.MaximumLength = info->path.Length + sizeof(WCHAR) + file_info->FileNameLength;
127     if (!(str.Buffer = HeapAlloc( GetProcessHeap(), 0, str.MaximumLength ))) return TRUE;
128     memcpy( str.Buffer, info->path.Buffer, info->path.Length );
129     len = info->path.Length / sizeof(WCHAR);
130     if (!len || str.Buffer[len-1] != '\\') str.Buffer[len++] = '\\';
131     memcpy( str.Buffer + len, file_info->FileName, file_info->FileNameLength );
132     str.Length = len * sizeof(WCHAR) + file_info->FileNameLength;
133 
134     unix_name.Buffer = NULL;
135     if (!wine_nt_to_unix_file_name( &str, &unix_name, OPEN_EXISTING, FALSE ) &&
136         !stat( unix_name.Buffer, &st ))
137     {
138         char *p = unix_name.Buffer + unix_name.Length - 1;
139 
140         /* skip trailing slashes */
141         while (p > unix_name.Buffer && *p == '/') p--;
142 
143         while (ret && p > unix_name.Buffer)
144         {
145             while (p > unix_name.Buffer && *p != '/') p--;
146             while (p > unix_name.Buffer && *p == '/') p--;
147             p[1] = 0;
148             if (!stat( unix_name.Buffer, &parent_st ) &&
149                 parent_st.st_dev == st.st_dev &&
150                 parent_st.st_ino == st.st_ino)
151             {
152                 WARN( "suppressing dir symlink %s pointing to parent %s\n",
153                       debugstr_wn( str.Buffer, str.Length/sizeof(WCHAR) ),
154                       debugstr_a( unix_name.Buffer ));
155                 ret = FALSE;
156             }
157         }
158     }
159     RtlFreeAnsiString( &unix_name );
160     RtlFreeUnicodeString( &str );
161     return ret;
162 }
163 
164 
165 /***********************************************************************
166  *           FILE_SetDosError
167  *
168  * Set the DOS error code from errno.
169  */
170 void FILE_SetDosError(void)
171 {
172     int save_errno = errno; /* errno gets overwritten by printf */
173 
174     TRACE("errno = %d %s\n", errno, strerror(errno));
175     switch (save_errno)
176     {
177     case EAGAIN:
178         SetLastError( ERROR_SHARING_VIOLATION );
179         break;
180     case EBADF:
181         SetLastError( ERROR_INVALID_HANDLE );
182         break;
183     case ENOSPC:
184         SetLastError( ERROR_HANDLE_DISK_FULL );
185         break;
186     case EACCES:
187     case EPERM:
188     case EROFS:
189         SetLastError( ERROR_ACCESS_DENIED );
190         break;
191     case EBUSY:
192         SetLastError( ERROR_LOCK_VIOLATION );
193         break;
194     case ENOENT:
195         SetLastError( ERROR_FILE_NOT_FOUND );
196         break;
197     case EISDIR:
198         SetLastError( ERROR_CANNOT_MAKE );
199         break;
200     case ENFILE:
201     case EMFILE:
202         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
203         break;
204     case EEXIST:
205         SetLastError( ERROR_FILE_EXISTS );
206         break;
207     case EINVAL:
208     case ESPIPE:
209         SetLastError( ERROR_SEEK );
210         break;
211     case ENOTEMPTY:
212         SetLastError( ERROR_DIR_NOT_EMPTY );
213         break;
214     case ENOEXEC:
215         SetLastError( ERROR_BAD_FORMAT );
216         break;
217     case ENOTDIR:
218         SetLastError( ERROR_PATH_NOT_FOUND );
219         break;
220     case EXDEV:
221         SetLastError( ERROR_NOT_SAME_DEVICE );
222         break;
223     default:
224         WARN("unknown file error: %s\n", strerror(save_errno) );
225         SetLastError( ERROR_GEN_FAILURE );
226         break;
227     }
228     errno = save_errno;
229 }
230 
231 
232 /***********************************************************************
233  *           FILE_name_AtoW
234  *
235  * Convert a file name to Unicode, taking into account the OEM/Ansi API mode.
236  *
237  * If alloc is FALSE uses the TEB static buffer, so it can only be used when
238  * there is no possibility for the function to do that twice, taking into
239  * account any called function.
240  */
241 WCHAR *FILE_name_AtoW( LPCSTR name, BOOL alloc )
242 {
243     ANSI_STRING str;
244     UNICODE_STRING strW, *pstrW;
245     NTSTATUS status;
246 
247     RtlInitAnsiString( &str, name );
248     pstrW = alloc ? &strW : &NtCurrentTeb()->StaticUnicodeString;
249     if (oem_file_apis)
250         status = RtlOemStringToUnicodeString( pstrW, &str, alloc );
251     else
252         status = RtlAnsiStringToUnicodeString( pstrW, &str, alloc );
253     if (status == STATUS_SUCCESS) return pstrW->Buffer;
254 
255     if (status == STATUS_BUFFER_OVERFLOW)
256         SetLastError( ERROR_FILENAME_EXCED_RANGE );
257     else
258         SetLastError( RtlNtStatusToDosError(status) );
259     return NULL;
260 }
261 
262 
263 /***********************************************************************
264  *           FILE_name_WtoA
265  *
266  * Convert a file name back to OEM/Ansi. Returns number of bytes copied.
267  */
268 DWORD FILE_name_WtoA( LPCWSTR src, INT srclen, LPSTR dest, INT destlen )
269 {
270     DWORD ret;
271 
272     if (srclen < 0) srclen = strlenW( src ) + 1;
273     if (oem_file_apis)
274         RtlUnicodeToOemN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) );
275     else
276         RtlUnicodeToMultiByteN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) );
277     return ret;
278 }
279 
280 
281 /**************************************************************************
282  *              SetFileApisToOEM   (KERNEL32.@)
283  */
284 VOID WINAPI SetFileApisToOEM(void)
285 {
286     oem_file_apis = TRUE;
287 }
288 
289 
290 /**************************************************************************
291  *              SetFileApisToANSI   (KERNEL32.@)
292  */
293 VOID WINAPI SetFileApisToANSI(void)
294 {
295     oem_file_apis = FALSE;
296 }
297 
298 
299 /******************************************************************************
300  *              AreFileApisANSI   (KERNEL32.@)
301  *
302  *  Determines if file functions are using ANSI
303  *
304  * RETURNS
305  *    TRUE:  Set of file functions is using ANSI code page
306  *    FALSE: Set of file functions is using OEM code page
307  */
308 BOOL WINAPI AreFileApisANSI(void)
309 {
310     return !oem_file_apis;
311 }
312 
313 
314 /**************************************************************************
315  *                      Operations on file handles                        *
316  **************************************************************************/
317 
318 /***********************************************************************
319  *           FILE_InitProcessDosHandles
320  *
321  * Allocates the default DOS handles for a process. Called either by
322  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
323  */
324 static void FILE_InitProcessDosHandles( void )
325 {
326     static BOOL init_done /* = FALSE */;
327     HANDLE cp = GetCurrentProcess();
328 
329     if (init_done) return;
330     init_done = TRUE;
331     DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
332                     0, TRUE, DUPLICATE_SAME_ACCESS);
333     DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
334                     0, TRUE, DUPLICATE_SAME_ACCESS);
335     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
336                     0, TRUE, DUPLICATE_SAME_ACCESS);
337     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
338                     0, TRUE, DUPLICATE_SAME_ACCESS);
339     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
340                     0, TRUE, DUPLICATE_SAME_ACCESS);
341 }
342 
343 
344 /******************************************************************
345  *              FILE_ReadWriteApc (internal)
346  */
347 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG reserved)
348 {
349     LPOVERLAPPED_COMPLETION_ROUTINE  cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
350 
351     cr(RtlNtStatusToDosError(io_status->u.Status), io_status->Information, (LPOVERLAPPED)io_status);
352 }
353 
354 
355 /***********************************************************************
356  *              ReadFileEx                (KERNEL32.@)
357  */
358 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
359                        LPOVERLAPPED overlapped,
360                        LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
361 {
362     LARGE_INTEGER       offset;
363     NTSTATUS            status;
364     PIO_STATUS_BLOCK    io_status;
365 
366     TRACE("(hFile=%p, buffer=%p, bytes=%u, ovl=%p, ovl_fn=%p)\n", hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
367 
368     if (!overlapped)
369     {
370         SetLastError(ERROR_INVALID_PARAMETER);
371         return FALSE;
372     }
373 
374     offset.u.LowPart = overlapped->u.s.Offset;
375     offset.u.HighPart = overlapped->u.s.OffsetHigh;
376     io_status = (PIO_STATUS_BLOCK)overlapped;
377     io_status->u.Status = STATUS_PENDING;
378     io_status->Information = 0;
379 
380     status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
381                         io_status, buffer, bytesToRead, &offset, NULL);
382 
383     if (status)
384     {
385         SetLastError( RtlNtStatusToDosError(status) );
386         return FALSE;
387     }
388     return TRUE;
389 }
390 
391 
392 /***********************************************************************
393  *              ReadFileScatter                (KERNEL32.@)
394  */
395 BOOL WINAPI ReadFileScatter( HANDLE file, FILE_SEGMENT_ELEMENT *segments, DWORD count,
396                              LPDWORD reserved, LPOVERLAPPED overlapped )
397 {
398     PIO_STATUS_BLOCK io_status;
399     LARGE_INTEGER offset;
400     NTSTATUS status;
401 
402     TRACE( "(%p %p %u %p)\n", file, segments, count, overlapped );
403 
404     offset.u.LowPart = overlapped->u.s.Offset;
405     offset.u.HighPart = overlapped->u.s.OffsetHigh;
406     io_status = (PIO_STATUS_BLOCK)overlapped;
407     io_status->u.Status = STATUS_PENDING;
408     io_status->Information = 0;
409 
410     status = NtReadFileScatter( file, NULL, NULL, NULL, io_status, segments, count, &offset, NULL );
411     if (status) SetLastError( RtlNtStatusToDosError(status) );
412     return !status;
413 }
414 
415 
416 /***********************************************************************
417  *              ReadFile                (KERNEL32.@)
418  */
419 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
420                       LPDWORD bytesRead, LPOVERLAPPED overlapped )
421 {
422     LARGE_INTEGER       offset;
423     PLARGE_INTEGER      poffset = NULL;
424     IO_STATUS_BLOCK     iosb;
425     PIO_STATUS_BLOCK    io_status = &iosb;
426     HANDLE              hEvent = 0;
427     NTSTATUS            status;
428     LPVOID              cvalue = NULL;
429 
430     TRACE("%p %p %d %p %p\n", hFile, buffer, bytesToRead,
431           bytesRead, overlapped );
432 
433     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
434     if (!bytesToRead) return TRUE;
435 
436     if (is_console_handle(hFile))
437         return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
438 
439     if (overlapped != NULL)
440     {
441         offset.u.LowPart = overlapped->u.s.Offset;
442         offset.u.HighPart = overlapped->u.s.OffsetHigh;
443         poffset = &offset;
444         hEvent = overlapped->hEvent;
445         io_status = (PIO_STATUS_BLOCK)overlapped;
446         if (((ULONG_PTR)hEvent & 1) == 0) cvalue = overlapped;
447     }
448     io_status->u.Status = STATUS_PENDING;
449     io_status->Information = 0;
450 
451     status = NtReadFile(hFile, hEvent, NULL, cvalue, io_status, buffer, bytesToRead, poffset, NULL);
452 
453     if (status == STATUS_PENDING && !overlapped)
454     {
455         WaitForSingleObject( hFile, INFINITE );
456         status = io_status->u.Status;
457     }
458 
459     if (status != STATUS_PENDING && bytesRead)
460         *bytesRead = io_status->Information;
461 
462     if (status && status != STATUS_END_OF_FILE && status != STATUS_TIMEOUT)
463     {
464         SetLastError( RtlNtStatusToDosError(status) );
465         return FALSE;
466     }
467     return TRUE;
468 }
469 
470 
471 /***********************************************************************
472  *              WriteFileEx                (KERNEL32.@)
473  */
474 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
475                         LPOVERLAPPED overlapped,
476                         LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
477 {
478     LARGE_INTEGER       offset;
479     NTSTATUS            status;
480     PIO_STATUS_BLOCK    io_status;
481 
482     TRACE("%p %p %d %p %p\n", hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
483 
484     if (overlapped == NULL)
485     {
486         SetLastError(ERROR_INVALID_PARAMETER);
487         return FALSE;
488     }
489     offset.u.LowPart = overlapped->u.s.Offset;
490     offset.u.HighPart = overlapped->u.s.OffsetHigh;
491 
492     io_status = (PIO_STATUS_BLOCK)overlapped;
493     io_status->u.Status = STATUS_PENDING;
494     io_status->Information = 0;
495 
496     status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
497                          io_status, buffer, bytesToWrite, &offset, NULL);
498 
499     if (status) SetLastError( RtlNtStatusToDosError(status) );
500     return !status;
501 }
502 
503 
504 /***********************************************************************
505  *              WriteFileGather                (KERNEL32.@)
506  */
507 BOOL WINAPI WriteFileGather( HANDLE file, FILE_SEGMENT_ELEMENT *segments, DWORD count,
508                              LPDWORD reserved, LPOVERLAPPED overlapped )
509 {
510     PIO_STATUS_BLOCK io_status;
511     LARGE_INTEGER offset;
512     NTSTATUS status;
513 
514     TRACE( "%p %p %u %p\n", file, segments, count, overlapped );
515 
516     offset.u.LowPart = overlapped->u.s.Offset;
517     offset.u.HighPart = overlapped->u.s.OffsetHigh;
518     io_status = (PIO_STATUS_BLOCK)overlapped;
519     io_status->u.Status = STATUS_PENDING;
520     io_status->Information = 0;
521 
522     status = NtWriteFileGather( file, NULL, NULL, NULL, io_status, segments, count, &offset, NULL );
523     if (status) SetLastError( RtlNtStatusToDosError(status) );
524     return !status;
525 }
526 
527 
528 /***********************************************************************
529  *             WriteFile               (KERNEL32.@)
530  */
531 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
532                        LPDWORD bytesWritten, LPOVERLAPPED overlapped )
533 {
534     HANDLE hEvent = NULL;
535     LARGE_INTEGER offset;
536     PLARGE_INTEGER poffset = NULL;
537     NTSTATUS status;
538     IO_STATUS_BLOCK iosb;
539     PIO_STATUS_BLOCK piosb = &iosb;
540     LPVOID cvalue = NULL;
541 
542     TRACE("%p %p %d %p %p\n", hFile, buffer, bytesToWrite, bytesWritten, overlapped );
543 
544     if (is_console_handle(hFile))
545         return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
546 
547     if (overlapped)
548     {
549         offset.u.LowPart = overlapped->u.s.Offset;
550         offset.u.HighPart = overlapped->u.s.OffsetHigh;
551         poffset = &offset;
552         hEvent = overlapped->hEvent;
553         piosb = (PIO_STATUS_BLOCK)overlapped;
554         if (((ULONG_PTR)hEvent & 1) == 0) cvalue = overlapped;
555     }
556     piosb->u.Status = STATUS_PENDING;
557     piosb->Information = 0;
558 
559     status = NtWriteFile(hFile, hEvent, NULL, cvalue, piosb,
560                          buffer, bytesToWrite, poffset, NULL);
561 
562     /* FIXME: NtWriteFile does not always cause page faults, generate them now */
563     if (status == STATUS_INVALID_USER_BUFFER && !IsBadReadPtr( buffer, bytesToWrite ))
564     {
565         status = NtWriteFile(hFile, hEvent, NULL, cvalue, piosb,
566                              buffer, bytesToWrite, poffset, NULL);
567         if (status != STATUS_INVALID_USER_BUFFER)
568             FIXME("Could not access memory (%p,%d) at first, now OK. Protected by DIBSection code?\n",
569                   buffer, bytesToWrite);
570     }
571 
572     if (status == STATUS_PENDING && !overlapped)
573     {
574         WaitForSingleObject( hFile, INFINITE );
575         status = piosb->u.Status;
576     }
577 
578     if (status != STATUS_PENDING && bytesWritten)
579         *bytesWritten = piosb->Information;
580 
581     if (status && status != STATUS_TIMEOUT)
582     {
583         SetLastError( RtlNtStatusToDosError(status) );
584         return FALSE;
585     }
586     return TRUE;
587 }
588 
589 
590 /***********************************************************************
591  *              GetOverlappedResult     (KERNEL32.@)
592  *
593  * Check the result of an Asynchronous data transfer from a file.
594  *
595  * Parameters
596  *   HANDLE hFile                 [in] handle of file to check on
597  *   LPOVERLAPPED lpOverlapped    [in/out] pointer to overlapped
598  *   LPDWORD lpTransferred        [in/out] number of bytes transferred
599  *   BOOL bWait                   [in] wait for the transfer to complete ?
600  *
601  * RETURNS
602  *   TRUE on success
603  *   FALSE on failure
604  *
605  *  If successful (and relevant) lpTransferred will hold the number of
606  *   bytes transferred during the async operation.
607  */
608 BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
609                                 LPDWORD lpTransferred, BOOL bWait)
610 {
611     NTSTATUS status;
612 
613     TRACE( "(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait );
614 
615     if ( lpOverlapped == NULL )
616     {
617         ERR("lpOverlapped was null\n");
618         return FALSE;
619     }
620 
621     status = lpOverlapped->Internal;
622     if (status == STATUS_PENDING)
623     {
624         if (!bWait)
625         {
626             SetLastError( ERROR_IO_INCOMPLETE );
627             return FALSE;
628         }
629 
630         if (WaitForSingleObject( lpOverlapped->hEvent ? lpOverlapped->hEvent : hFile,
631                                  INFINITE ) == WAIT_FAILED)
632             return FALSE;
633         status = lpOverlapped->Internal;
634     }
635 
636     if (lpTransferred) *lpTransferred = lpOverlapped->InternalHigh;
637 
638     if (status) SetLastError( RtlNtStatusToDosError(status) );
639     return !status;
640 }
641 
642 /***********************************************************************
643  *             CancelIo                   (KERNEL32.@)
644  *
645  * Cancels pending I/O operations initiated by the current thread on a file.
646  *
647  * PARAMS
648  *  handle [I] File handle.
649  *
650  * RETURNS
651  *  Success: TRUE.
652  *  Failure: FALSE, check GetLastError().
653  */
654 BOOL WINAPI CancelIo(HANDLE handle)
655 {
656     IO_STATUS_BLOCK    io_status;
657 
658     NtCancelIoFile(handle, &io_status);
659     if (io_status.u.Status)
660     {
661         SetLastError( RtlNtStatusToDosError( io_status.u.Status ) );
662         return FALSE;
663     }
664     return TRUE;
665 }
666 
667 /***********************************************************************
668  *           _hread   (KERNEL32.@)
669  */
670 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
671 {
672     return _lread( hFile, buffer, count );
673 }
674 
675 
676 /***********************************************************************
677  *           _hwrite   (KERNEL32.@)
678  *
679  *      experimentation yields that _lwrite:
680  *              o truncates the file at the current position with
681  *                a 0 len write
682  *              o returns 0 on a 0 length write
683  *              o works with console handles
684  *
685  */
686 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
687 {
688     DWORD result;
689 
690     TRACE("%d %p %d\n", handle, buffer, count );
691 
692     if (!count)
693     {
694         /* Expand or truncate at current position */
695         if (!SetEndOfFile( LongToHandle(handle) )) return HFILE_ERROR;
696         return 0;
697     }
698     if (!WriteFile( LongToHandle(handle), buffer, count, &result, NULL ))
699         return HFILE_ERROR;
700     return result;
701 }
702 
703 
704 /***********************************************************************
705  *           _lclose   (KERNEL32.@)
706  */
707 HFILE WINAPI _lclose( HFILE hFile )
708 {
709     TRACE("handle %d\n", hFile );
710     return CloseHandle( LongToHandle(hFile) ) ? 0 : HFILE_ERROR;
711 }
712 
713 
714 /***********************************************************************
715  *           _lcreat   (KERNEL32.@)
716  */
717 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
718 {
719     HANDLE hfile;
720 
721     /* Mask off all flags not explicitly allowed by the doc */
722     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
723     TRACE("%s %02x\n", path, attr );
724     hfile = CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
725                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
726                                CREATE_ALWAYS, attr, 0 );
727     return HandleToLong(hfile);
728 }
729 
730 
731 /***********************************************************************
732  *           _lopen   (KERNEL32.@)
733  */
734 HFILE WINAPI _lopen( LPCSTR path, INT mode )
735 {
736     HANDLE hfile;
737 
738     TRACE("(%s,%04x)\n", debugstr_a(path), mode );
739     hfile = create_file_OF( path, mode & ~OF_CREATE );
740     return HandleToLong(hfile);
741 }
742 
743 /***********************************************************************
744  *           _lread   (KERNEL32.@)
745  */
746 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
747 {
748     DWORD result;
749     if (!ReadFile( LongToHandle(handle), buffer, count, &result, NULL ))
750         return HFILE_ERROR;
751     return result;
752 }
753 
754 
755 /***********************************************************************
756  *           _llseek   (KERNEL32.@)
757  */
758 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
759 {
760     return SetFilePointer( LongToHandle(hFile), lOffset, NULL, nOrigin );
761 }
762 
763 
764 /***********************************************************************
765  *           _lwrite   (KERNEL32.@)
766  */
767 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
768 {
769     return (UINT)_hwrite( hFile, buffer, (LONG)count );
770 }
771 
772 
773 /***********************************************************************
774  *           FlushFileBuffers   (KERNEL32.@)
775  */
776 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
777 {
778     NTSTATUS            nts;
779     IO_STATUS_BLOCK     ioblk;
780 
781     if (is_console_handle( hFile ))
782     {
783         /* this will fail (as expected) for an output handle */
784         return FlushConsoleInputBuffer( hFile );
785     }
786     nts = NtFlushBuffersFile( hFile, &ioblk );
787     if (nts != STATUS_SUCCESS)
788     {
789         SetLastError( RtlNtStatusToDosError( nts ) );
790         return FALSE;
791     }
792 
793     return TRUE;
794 }
795 
796 
797 /***********************************************************************
798  *           GetFileType   (KERNEL32.@)
799  */
800 DWORD WINAPI GetFileType( HANDLE hFile )
801 {
802     FILE_FS_DEVICE_INFORMATION info;
803     IO_STATUS_BLOCK io;
804     NTSTATUS status;
805 
806     if (is_console_handle( hFile )) return FILE_TYPE_CHAR;
807 
808     status = NtQueryVolumeInformationFile( hFile, &io, &info, sizeof(info), FileFsDeviceInformation );
809     if (status != STATUS_SUCCESS)
810     {
811         SetLastError( RtlNtStatusToDosError(status) );
812         return FILE_TYPE_UNKNOWN;
813     }
814 
815     switch(info.DeviceType)
816     {
817     case FILE_DEVICE_NULL:
818     case FILE_DEVICE_SERIAL_PORT:
819     case FILE_DEVICE_PARALLEL_PORT:
820     case FILE_DEVICE_TAPE:
821     case FILE_DEVICE_UNKNOWN:
822         return FILE_TYPE_CHAR;
823     case FILE_DEVICE_NAMED_PIPE:
824         return FILE_TYPE_PIPE;
825     default:
826         return FILE_TYPE_DISK;
827     }
828 }
829 
830 
831 /***********************************************************************
832  *             GetFileInformationByHandle   (KERNEL32.@)
833  */
834 BOOL WINAPI GetFileInformationByHandle( HANDLE hFile, BY_HANDLE_FILE_INFORMATION *info )
835 {
836     FILE_ALL_INFORMATION all_info;
837     IO_STATUS_BLOCK io;
838     NTSTATUS status;
839 
840     status = NtQueryInformationFile( hFile, &io, &all_info, sizeof(all_info), FileAllInformation );
841     if (status == STATUS_SUCCESS)
842     {
843         info->dwFileAttributes                = all_info.BasicInformation.FileAttributes;
844         info->ftCreationTime.dwHighDateTime   = all_info.BasicInformation.CreationTime.u.HighPart;
845         info->ftCreationTime.dwLowDateTime    = all_info.BasicInformation.CreationTime.u.LowPart;
846         info->ftLastAccessTime.dwHighDateTime = all_info.BasicInformation.LastAccessTime.u.HighPart;
847         info->ftLastAccessTime.dwLowDateTime  = all_info.BasicInformation.LastAccessTime.u.LowPart;
848         info->ftLastWriteTime.dwHighDateTime  = all_info.BasicInformation.LastWriteTime.u.HighPart;
849         info->ftLastWriteTime.dwLowDateTime   = all_info.BasicInformation.LastWriteTime.u.LowPart;
850         info->dwVolumeSerialNumber            = 0;  /* FIXME */
851         info->nFileSizeHigh                   = all_info.StandardInformation.EndOfFile.u.HighPart;
852         info->nFileSizeLow                    = all_info.StandardInformation.EndOfFile.u.LowPart;
853         info->nNumberOfLinks                  = all_info.StandardInformation.NumberOfLinks;
854         info->nFileIndexHigh                  = all_info.InternalInformation.IndexNumber.u.HighPart;
855         info->nFileIndexLow                   = all_info.InternalInformation.IndexNumber.u.LowPart;
856         return TRUE;
857     }
858     SetLastError( RtlNtStatusToDosError(status) );
859     return FALSE;
860 }
861 
862 
863 /***********************************************************************
864  *           GetFileSize   (KERNEL32.@)
865  *
866  * Retrieve the size of a file.
867  *
868  * PARAMS
869  *  hFile        [I] File to retrieve size of.
870  *  filesizehigh [O] On return, the high bits of the file size.
871  *
872  * RETURNS
873  *  Success: The low bits of the file size.
874  *  Failure: INVALID_FILE_SIZE. As this is could also be a success value,
875  *           check GetLastError() for values other than ERROR_SUCCESS.
876  */
877 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
878 {
879     LARGE_INTEGER size;
880     if (!GetFileSizeEx( hFile, &size )) return INVALID_FILE_SIZE;
881     if (filesizehigh) *filesizehigh = size.u.HighPart;
882     if (size.u.LowPart == INVALID_FILE_SIZE) SetLastError(0);
883     return size.u.LowPart;
884 }
885 
886 
887 /***********************************************************************
888  *           GetFileSizeEx   (KERNEL32.@)
889  *
890  * Retrieve the size of a file.
891  *
892  * PARAMS
893  *  hFile        [I] File to retrieve size of.
894  *  lpFileSIze   [O] On return, the size of the file.
895  *
896  * RETURNS
897  *  Success: TRUE.
898  *  Failure: FALSE, check GetLastError().
899  */
900 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
901 {
902     FILE_END_OF_FILE_INFORMATION info;
903     IO_STATUS_BLOCK io;
904     NTSTATUS status;
905 
906     status = NtQueryInformationFile( hFile, &io, &info, sizeof(info), FileEndOfFileInformation );
907     if (status == STATUS_SUCCESS)
908     {
909         *lpFileSize = info.EndOfFile;
910         return TRUE;
911     }
912     SetLastError( RtlNtStatusToDosError(status) );
913     return FALSE;
914 }
915 
916 
917 /**************************************************************************
918  *           SetEndOfFile   (KERNEL32.@)
919  *
920  * Sets the current position as the end of the file.
921  *
922  * PARAMS
923  *  hFile [I] File handle.
924  *
925  * RETURNS
926  *  Success: TRUE.
927  *  Failure: FALSE, check GetLastError().
928  */
929 BOOL WINAPI SetEndOfFile( HANDLE hFile )
930 {
931     FILE_POSITION_INFORMATION pos;
932     FILE_END_OF_FILE_INFORMATION eof;
933     IO_STATUS_BLOCK io;
934     NTSTATUS status;
935 
936     status = NtQueryInformationFile( hFile, &io, &pos, sizeof(pos), FilePositionInformation );
937     if (status == STATUS_SUCCESS)
938     {
939         eof.EndOfFile = pos.CurrentByteOffset;
940         status = NtSetInformationFile( hFile, &io, &eof, sizeof(eof), FileEndOfFileInformation );