Enable querying of IID_FilterGraph interface from filtergraph manager
[wine] / files / 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 <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 #endif
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
50 #endif
51 #include <time.h>
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
55 #ifdef HAVE_UTIME_H
56 # include <utime.h>
57 #endif
58 #ifdef HAVE_IO_H
59 # include <io.h>
60 #endif
61
62 #define NONAMELESSUNION
63 #define NONAMELESSSTRUCT
64 #include "winerror.h"
65 #include "ntstatus.h"
66 #include "windef.h"
67 #include "winbase.h"
68 #include "winreg.h"
69 #include "winternl.h"
70 #include "wine/winbase16.h"
71 #include "wine/server.h"
72
73 #include "file.h"
74 #include "wincon.h"
75 #include "kernel_private.h"
76
77 #include "smb.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
80
81 WINE_DEFAULT_DEBUG_CHANNEL(file);
82
83
84 /***********************************************************************
85  *              FILE_ConvertOFMode
86  *
87  * Convert OF_* mode into flags for CreateFile.
88  */
89 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
90 {
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     switch(mode & 0x70)
99     {
100     case OF_SHARE_EXCLUSIVE:  *sharing = 0; break;
101     case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
102     case OF_SHARE_DENY_READ:  *sharing = FILE_SHARE_WRITE; break;
103     case OF_SHARE_DENY_NONE:
104     case OF_SHARE_COMPAT:
105     default:                  *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
106     }
107 }
108
109
110 /***********************************************************************
111  *           FILE_SetDosError
112  *
113  * Set the DOS error code from errno.
114  */
115 void FILE_SetDosError(void)
116 {
117     int save_errno = errno; /* errno gets overwritten by printf */
118
119     TRACE("errno = %d %s\n", errno, strerror(errno));
120     switch (save_errno)
121     {
122     case EAGAIN:
123         SetLastError( ERROR_SHARING_VIOLATION );
124         break;
125     case EBADF:
126         SetLastError( ERROR_INVALID_HANDLE );
127         break;
128     case ENOSPC:
129         SetLastError( ERROR_HANDLE_DISK_FULL );
130         break;
131     case EACCES:
132     case EPERM:
133     case EROFS:
134         SetLastError( ERROR_ACCESS_DENIED );
135         break;
136     case EBUSY:
137         SetLastError( ERROR_LOCK_VIOLATION );
138         break;
139     case ENOENT:
140         SetLastError( ERROR_FILE_NOT_FOUND );
141         break;
142     case EISDIR:
143         SetLastError( ERROR_CANNOT_MAKE );
144         break;
145     case ENFILE:
146     case EMFILE:
147         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
148         break;
149     case EEXIST:
150         SetLastError( ERROR_FILE_EXISTS );
151         break;
152     case EINVAL:
153     case ESPIPE:
154         SetLastError( ERROR_SEEK );
155         break;
156     case ENOTEMPTY:
157         SetLastError( ERROR_DIR_NOT_EMPTY );
158         break;
159     case ENOEXEC:
160         SetLastError( ERROR_BAD_FORMAT );
161         break;
162     case ENOTDIR:
163         SetLastError( ERROR_PATH_NOT_FOUND );
164         break;
165     case EXDEV:
166         SetLastError( ERROR_NOT_SAME_DEVICE );
167         break;
168     default:
169         WARN("unknown file error: %s\n", strerror(save_errno) );
170         SetLastError( ERROR_GEN_FAILURE );
171         break;
172     }
173     errno = save_errno;
174 }
175
176
177 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
178 {
179     HANDLE ret;
180     DWORD len = 0;
181
182     if (name && (len = strlenW(name)) > MAX_PATH)
183     {
184         SetLastError( ERROR_FILENAME_EXCED_RANGE );
185         return 0;
186     }
187     SERVER_START_REQ( open_named_pipe )
188     {
189         req->access = access;
190         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
191         SetLastError(0);
192         wine_server_add_data( req, name, len * sizeof(WCHAR) );
193         wine_server_call_err( req );
194         ret = reply->handle;
195     }
196     SERVER_END_REQ;
197     TRACE("Returned %p\n",ret);
198     return ret;
199 }
200
201 /*************************************************************************
202  * CreateFileW [KERNEL32.@]  Creates or opens a file or other object
203  *
204  * Creates or opens an object, and returns a handle that can be used to
205  * access that object.
206  *
207  * PARAMS
208  *
209  * filename     [in] pointer to filename to be accessed
210  * access       [in] access mode requested
211  * sharing      [in] share mode
212  * sa           [in] pointer to security attributes
213  * creation     [in] how to create the file
214  * attributes   [in] attributes for newly created file
215  * template     [in] handle to file with extended attributes to copy
216  *
217  * RETURNS
218  *   Success: Open handle to specified file
219  *   Failure: INVALID_HANDLE_VALUE
220  *
221  * NOTES
222  *  Should call SetLastError() on failure.
223  *
224  * BUGS
225  *
226  * Doesn't support character devices, template files, or a
227  * lot of the 'attributes' flags yet.
228  */
229 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
230                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
231                               DWORD attributes, HANDLE template )
232 {
233     NTSTATUS status;
234     UINT options;
235     OBJECT_ATTRIBUTES attr;
236     UNICODE_STRING nameW;
237     IO_STATUS_BLOCK io;
238     HANDLE ret;
239     DWORD dosdev;
240     static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
241     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
242     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
243
244     static const char * const creation_name[5] =
245         { "CREATE_NEW", "CREATE_ALWAYS", "OPEN_EXISTING", "OPEN_ALWAYS", "TRUNCATE_EXISTING" };
246
247     static const UINT nt_disposition[5] =
248     {
249         FILE_CREATE,        /* CREATE_NEW */
250         FILE_OVERWRITE_IF,  /* CREATE_ALWAYS */
251         FILE_OPEN,          /* OPEN_EXISTING */
252         FILE_OPEN_IF,       /* OPEN_ALWAYS */
253         FILE_OVERWRITE      /* TRUNCATE_EXISTING */
254     };
255
256
257     /* sanity checks */
258
259     if (!filename || !filename[0])
260     {
261         SetLastError( ERROR_PATH_NOT_FOUND );
262         return INVALID_HANDLE_VALUE;
263     }
264
265     if (creation < CREATE_NEW || creation > TRUNCATE_EXISTING)
266     {
267         SetLastError( ERROR_INVALID_PARAMETER );
268         return INVALID_HANDLE_VALUE;
269     }
270
271     TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
272           (access & GENERIC_READ)?"GENERIC_READ ":"",
273           (access & GENERIC_WRITE)?"GENERIC_WRITE ":"",
274           (!access)?"QUERY_ACCESS ":"",
275           (sharing & FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
276           (sharing & FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
277           (sharing & FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
278           creation_name[creation - CREATE_NEW], attributes);
279
280     /* Open a console for CONIN$ or CONOUT$ */
281
282     if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
283     {
284         ret = OpenConsoleW(filename, access, (sa && sa->bInheritHandle), creation);
285         goto done;
286     }
287
288     if (!strncmpW(filename, bkslashes_with_dotW, 4))
289     {
290         static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
291         if(!strncmpiW(filename + 4, pipeW, 5))
292         {
293             TRACE("Opening a pipe: %s\n", debugstr_w(filename));
294             ret = FILE_OpenPipe( filename, access, sa );
295             goto done;
296         }
297         else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
298         {
299             dosdev = 0;
300         }
301         else if ((dosdev = RtlIsDosDeviceName_U( filename + 4 )))
302         {
303             dosdev += MAKELONG( 0, 4*sizeof(WCHAR) );  /* adjust position to start of filename */
304         }
305         else if (filename[4])
306         {
307             ret = VXD_Open( filename+4, access, sa );
308             goto done;
309         }
310         else
311         {
312             SetLastError( ERROR_INVALID_NAME );
313             return INVALID_HANDLE_VALUE;
314         }
315     }
316     else dosdev = RtlIsDosDeviceName_U( filename );
317
318     if (dosdev)
319     {
320         static const WCHAR conW[] = {'C','O','N'};
321
322         if (LOWORD(dosdev) == sizeof(conW) &&
323             !memicmpW( filename + HIWORD(dosdev)/sizeof(WCHAR), conW, sizeof(conW)))
324         {
325             switch (access & (GENERIC_READ|GENERIC_WRITE))
326             {
327             case GENERIC_READ:
328                 ret = OpenConsoleW(coninW, access, (sa && sa->bInheritHandle), creation);
329                 goto done;
330             case GENERIC_WRITE:
331                 ret = OpenConsoleW(conoutW, access, (sa && sa->bInheritHandle), creation);
332                 goto done;
333             default:
334                 SetLastError( ERROR_FILE_NOT_FOUND );
335                 return INVALID_HANDLE_VALUE;
336             }
337         }
338     }
339
340     if (!RtlDosPathNameToNtPathName_U( filename, &nameW, NULL, NULL ))
341     {
342         SetLastError( ERROR_PATH_NOT_FOUND );
343         return INVALID_HANDLE_VALUE;
344     }
345
346     /* now call NtCreateFile */
347
348     options = 0;
349     if (attributes & FILE_FLAG_BACKUP_SEMANTICS)
350         options |= FILE_OPEN_FOR_BACKUP_INTENT;
351     else
352         options |= FILE_NON_DIRECTORY_FILE;
353     if (attributes & FILE_FLAG_DELETE_ON_CLOSE)
354         options |= FILE_DELETE_ON_CLOSE;
355     if (!(attributes & FILE_FLAG_OVERLAPPED))
356         options |= FILE_SYNCHRONOUS_IO_ALERT;
357     if (attributes & FILE_FLAG_RANDOM_ACCESS)
358         options |= FILE_RANDOM_ACCESS;
359     attributes &= FILE_ATTRIBUTE_VALID_FLAGS;
360
361     attr.Length = sizeof(attr);
362     attr.RootDirectory = 0;
363     attr.Attributes = OBJ_CASE_INSENSITIVE;
364     attr.ObjectName = &nameW;
365     attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL;
366     attr.SecurityQualityOfService = NULL;
367
368     if (sa && sa->bInheritHandle) attr.Attributes |= OBJ_INHERIT;
369
370     status = NtCreateFile( &ret, access, &attr, &io, NULL, attributes,
371                            sharing, nt_disposition[creation - CREATE_NEW],
372                            options, NULL, 0 );
373     if (status)
374     {
375         WARN("Unable to create file %s (status %lx)\n", debugstr_w(filename), status);
376         ret = INVALID_HANDLE_VALUE;
377
378         /* In the case file creation was rejected due to CREATE_NEW flag
379          * was specified and file with that name already exists, correct
380          * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
381          * Note: RtlNtStatusToDosError is not the subject to blame here.
382          */
383         if (status == STATUS_OBJECT_NAME_COLLISION)
384             SetLastError( ERROR_FILE_EXISTS );
385         else
386             SetLastError( RtlNtStatusToDosError(status) );
387     }
388     else SetLastError(0);
389     RtlFreeUnicodeString( &nameW );
390
391  done:
392     if (!ret) ret = INVALID_HANDLE_VALUE;
393     TRACE("returning %p\n", ret);
394     return ret;
395 }
396
397
398
399 /*************************************************************************
400  *              CreateFileA              (KERNEL32.@)
401  */
402 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
403                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
404                               DWORD attributes, HANDLE template)
405 {
406     UNICODE_STRING filenameW;
407     HANDLE ret = INVALID_HANDLE_VALUE;
408
409     if (!filename)
410     {
411         SetLastError( ERROR_INVALID_PARAMETER );
412         return INVALID_HANDLE_VALUE;
413     }
414
415     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
416     {
417         ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
418                           attributes, template);
419         RtlFreeUnicodeString(&filenameW);
420     }
421     else
422         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
423     return ret;
424 }
425
426
427 /***********************************************************************
428  *           FILE_FillInfo
429  *
430  * Fill a file information from a struct stat.
431  */
432 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
433 {
434     if (S_ISDIR(st->st_mode))
435         info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
436     else
437         info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
438     if (!(st->st_mode & S_IWUSR))
439         info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
440
441     RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
442     RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
443     RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
444
445     info->dwVolumeSerialNumber = 0;  /* FIXME */
446     if (S_ISDIR(st->st_mode))
447     {
448         info->nFileSizeHigh  = 0;
449         info->nFileSizeLow   = 0;
450         info->nNumberOfLinks = 1;
451     }
452     else
453     {
454         info->nFileSizeHigh  = st->st_size >> 32;
455         info->nFileSizeLow   = (DWORD)st->st_size;
456         info->nNumberOfLinks = st->st_nlink;
457     }
458     info->nFileIndexHigh = st->st_ino >> 32;
459     info->nFileIndexLow  = (DWORD)st->st_ino;
460 }
461
462
463 /***********************************************************************
464  *             GetFileInformationByHandle   (KERNEL32.@)
465  */
466 BOOL WINAPI GetFileInformationByHandle( HANDLE hFile, BY_HANDLE_FILE_INFORMATION *info )
467 {
468     NTSTATUS status;
469     int fd;
470     BOOL ret = FALSE;
471
472     TRACE("%p,%p\n", hFile, info);
473
474     if (!info) return 0;
475
476     if (!(status = wine_server_handle_to_fd( hFile, 0, &fd, NULL, NULL )))
477     {
478         struct stat st;
479
480         if (fstat( fd, &st ) == -1)
481             FILE_SetDosError();
482         else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
483             SetLastError( ERROR_INVALID_FUNCTION );
484         else
485         {
486             FILE_FillInfo( &st, info );
487             ret = TRUE;
488         }
489         wine_server_release_fd( hFile, fd );
490     }
491     else SetLastError( RtlNtStatusToDosError(status) );
492
493     return ret;
494 }
495
496
497 /***********************************************************************
498  *           GetFileTime   (KERNEL32.@)
499  */
500 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
501                            FILETIME *lpLastAccessTime,
502                            FILETIME *lpLastWriteTime )
503 {
504     BY_HANDLE_FILE_INFORMATION info;
505     if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
506     if (lpCreationTime)   *lpCreationTime   = info.ftCreationTime;
507     if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
508     if (lpLastWriteTime)  *lpLastWriteTime  = info.ftLastWriteTime;
509     return TRUE;
510 }
511
512
513 /***********************************************************************
514  *           GetTempFileNameA   (KERNEL32.@)
515  */
516 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
517                                   LPSTR buffer)
518 {
519     UNICODE_STRING pathW, prefixW;
520     WCHAR bufferW[MAX_PATH];
521     UINT ret;
522
523     if ( !path || !prefix || !buffer )
524     {
525         SetLastError( ERROR_INVALID_PARAMETER );
526         return 0;
527     }
528
529     RtlCreateUnicodeStringFromAsciiz(&pathW, path);
530     RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
531
532     ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
533     if (ret)
534         WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
535
536     RtlFreeUnicodeString(&pathW);
537     RtlFreeUnicodeString(&prefixW);
538     return ret;
539 }
540
541 /***********************************************************************
542  *           GetTempFileNameW   (KERNEL32.@)
543  */
544 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
545                                   LPWSTR buffer )
546 {
547     static const WCHAR formatW[] = {'%','x','.','t','m','p',0};
548
549     int i;
550     LPWSTR p;
551
552     if ( !path || !prefix || !buffer )
553     {
554         SetLastError( ERROR_INVALID_PARAMETER );
555         return 0;
556     }
557
558     strcpyW( buffer, path );
559     p = buffer + strlenW(buffer);
560
561     /* add a \, if there isn't one  */
562     if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
563
564     for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
565
566     unique &= 0xffff;
567
568     if (unique) sprintfW( p, formatW, unique );
569     else
570     {
571         /* get a "random" unique number and try to create the file */
572         HANDLE handle;
573         UINT num = GetTickCount() & 0xffff;
574
575         if (!num) num = 1;
576         unique = num;
577         do
578         {
579             sprintfW( p, formatW, unique );
580             handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
581                                   CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
582             if (handle != INVALID_HANDLE_VALUE)
583             {  /* We created it */
584                 TRACE("created %s\n", debugstr_w(buffer) );
585                 CloseHandle( handle );
586                 break;
587             }
588             if (GetLastError() != ERROR_FILE_EXISTS &&
589                 GetLastError() != ERROR_SHARING_VIOLATION)
590                 break;  /* No need to go on */
591             if (!(++unique & 0xffff)) unique = 1;
592         } while (unique != num);
593     }
594
595     TRACE("returning %s\n", debugstr_w(buffer) );
596     return unique;
597 }
598
599
600 /******************************************************************
601  *              FILE_ReadWriteApc (internal)
602  *
603  *
604  */
605 static void WINAPI      FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
606 {
607     LPOVERLAPPED_COMPLETION_ROUTINE  cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
608
609     cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
610 }
611
612 /***********************************************************************
613  *              ReadFileEx                (KERNEL32.@)
614  */
615 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
616                        LPOVERLAPPED overlapped,
617                        LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
618 {
619     LARGE_INTEGER       offset;
620     NTSTATUS            status;
621     PIO_STATUS_BLOCK    io_status;
622
623     if (!overlapped)
624     {
625         SetLastError(ERROR_INVALID_PARAMETER);
626         return FALSE;
627     }
628
629     offset.u.LowPart = overlapped->Offset;
630     offset.u.HighPart = overlapped->OffsetHigh;
631     io_status = (PIO_STATUS_BLOCK)overlapped;
632     io_status->u.Status = STATUS_PENDING;
633
634     status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
635                         io_status, buffer, bytesToRead, &offset, NULL);
636
637     if (status)
638     {
639         SetLastError( RtlNtStatusToDosError(status) );
640         return FALSE;
641     }
642     return TRUE;
643 }
644
645 /***********************************************************************
646  *              ReadFile                (KERNEL32.@)
647  */
648 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
649                       LPDWORD bytesRead, LPOVERLAPPED overlapped )
650 {
651     LARGE_INTEGER       offset;
652     PLARGE_INTEGER      poffset = NULL;
653     IO_STATUS_BLOCK     iosb;
654     PIO_STATUS_BLOCK    io_status = &iosb;
655     HANDLE              hEvent = 0;
656     NTSTATUS            status;
657         
658     TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
659           bytesRead, overlapped );
660
661     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
662     if (!bytesToRead) return TRUE;
663
664     if (IsBadReadPtr(buffer, bytesToRead))
665     {
666         SetLastError(ERROR_WRITE_FAULT); /* FIXME */
667         return FALSE;
668     }
669     if (is_console_handle(hFile))
670         return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
671
672     if (overlapped != NULL)
673     {
674         offset.u.LowPart = overlapped->Offset;
675         offset.u.HighPart = overlapped->OffsetHigh;
676         poffset = &offset;
677         hEvent = overlapped->hEvent;
678         io_status = (PIO_STATUS_BLOCK)overlapped;
679     }
680     io_status->u.Status = STATUS_PENDING;
681     io_status->Information = 0;
682
683     status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
684
685     if (status != STATUS_PENDING && bytesRead)
686         *bytesRead = io_status->Information;
687
688     if (status && status != STATUS_END_OF_FILE)
689     {
690         SetLastError( RtlNtStatusToDosError(status) );
691         return FALSE;
692     }
693     return TRUE;
694 }
695
696
697 /***********************************************************************
698  *              WriteFileEx                (KERNEL32.@)
699  */
700 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
701                         LPOVERLAPPED overlapped,
702                         LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
703 {
704     LARGE_INTEGER       offset;
705     NTSTATUS            status;
706     PIO_STATUS_BLOCK    io_status;
707
708     TRACE("%p %p %ld %p %p\n", 
709           hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
710
711     if (overlapped == NULL)
712     {
713         SetLastError(ERROR_INVALID_PARAMETER);
714         return FALSE;
715     }
716     offset.u.LowPart = overlapped->Offset;
717     offset.u.HighPart = overlapped->OffsetHigh;
718
719     io_status = (PIO_STATUS_BLOCK)overlapped;
720     io_status->u.Status = STATUS_PENDING;
721
722     status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
723                          io_status, buffer, bytesToWrite, &offset, NULL);
724
725     if (status) SetLastError( RtlNtStatusToDosError(status) );
726     return !status;
727 }
728
729 /***********************************************************************
730  *             WriteFile               (KERNEL32.@)
731  */
732 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
733                        LPDWORD bytesWritten, LPOVERLAPPED overlapped )
734 {
735     HANDLE hEvent = NULL;
736     LARGE_INTEGER offset;
737     PLARGE_INTEGER poffset = NULL;
738     NTSTATUS status;
739     IO_STATUS_BLOCK iosb;
740     PIO_STATUS_BLOCK piosb = &iosb;
741
742     TRACE("%p %p %ld %p %p\n", 
743           hFile, buffer, bytesToWrite, bytesWritten, overlapped );
744
745     if (is_console_handle(hFile))
746         return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
747
748     if (IsBadReadPtr(buffer, bytesToWrite))
749     {
750         SetLastError(ERROR_READ_FAULT); /* FIXME */
751         return FALSE;
752     }
753
754     if (overlapped)
755     {
756         offset.u.LowPart = overlapped->Offset;
757         offset.u.HighPart = overlapped->OffsetHigh;
758         poffset = &offset;
759         hEvent = overlapped->hEvent;
760         piosb = (PIO_STATUS_BLOCK)overlapped;
761     }
762     piosb->u.Status = STATUS_PENDING;
763     piosb->Information = 0;
764
765     status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
766                          buffer, bytesToWrite, poffset, NULL);
767     if (status)
768     {
769         SetLastError( RtlNtStatusToDosError(status) );
770         return FALSE;
771     }
772     if (bytesWritten) *bytesWritten = piosb->Information;
773
774     return TRUE;
775 }
776
777
778 /***********************************************************************
779  *           SetFilePointer   (KERNEL32.@)
780  */
781 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
782                              DWORD method )
783 {
784     static const int whence[3] = { SEEK_SET, SEEK_CUR, SEEK_END };
785     DWORD ret = INVALID_SET_FILE_POINTER;
786     NTSTATUS status;
787     int fd;
788
789     TRACE("handle %p offset %ld high %ld origin %ld\n",
790           hFile, distance, highword?*highword:0, method );
791
792     if (method > FILE_END)
793     {
794         SetLastError( ERROR_INVALID_PARAMETER );
795         return ret;
796     }
797
798     if (!(status = wine_server_handle_to_fd( hFile, 0, &fd, NULL, NULL )))
799     {
800         off_t pos, res;
801
802         if (highword) pos = ((off_t)*highword << 32) | (ULONG)distance;
803         else pos = (off_t)distance;
804         if ((res = lseek( fd, pos, whence[method] )) == (off_t)-1)
805         {
806             /* also check EPERM due to SuSE7 2.2.16 lseek() EPERM kernel bug */
807             if (((errno == EINVAL) || (errno == EPERM)) && (method != FILE_BEGIN) && (pos < 0))
808                 SetLastError( ERROR_NEGATIVE_SEEK );
809             else
810                 FILE_SetDosError();
811         }
812         else
813         {
814             ret = (DWORD)res;
815             if (highword) *highword = (res >> 32);
816             if (ret == INVALID_SET_FILE_POINTER) SetLastError( 0 );
817         }
818         wine_server_release_fd( hFile, fd );
819     }
820     else SetLastError( RtlNtStatusToDosError(status) );
821
822     return ret;
823 }
824
825
826 /*************************************************************************
827  *           SetHandleCount   (KERNEL32.@)
828  */
829 UINT WINAPI SetHandleCount( UINT count )
830 {
831     return min( 256, count );
832 }
833
834
835 /**************************************************************************
836  *           SetEndOfFile   (KERNEL32.@)
837  */
838 BOOL WINAPI SetEndOfFile( HANDLE hFile )
839 {
840     BOOL ret;
841     SERVER_START_REQ( truncate_file )
842     {
843         req->handle = hFile;
844         ret = !wine_server_call_err( req );
845     }
846     SERVER_END_REQ;
847     return ret;
848 }
849
850
851 /***********************************************************************
852  *           GetFileType   (KERNEL32.@)
853  */
854 DWORD WINAPI GetFileType( HANDLE hFile )
855 {
856     NTSTATUS status;
857     int fd;
858     DWORD ret = FILE_TYPE_UNKNOWN;
859
860     if (is_console_handle( hFile ))
861         return FILE_TYPE_CHAR;
862
863     if (!(status = wine_server_handle_to_fd( hFile, 0, &fd, NULL, NULL )))
864     {
865         struct stat st;
866
867         if (fstat( fd, &st ) == -1)
868             FILE_SetDosError();
869         else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
870             ret = FILE_TYPE_PIPE;
871         else if (S_ISCHR(st.st_mode))
872             ret = FILE_TYPE_CHAR;
873         else
874             ret = FILE_TYPE_DISK;
875         wine_server_release_fd( hFile, fd );
876     }
877     else SetLastError( RtlNtStatusToDosError(status) );
878
879     return ret;
880 }
881
882
883 /**************************************************************************
884  *           CopyFileW   (KERNEL32.@)
885  */
886 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
887 {
888     HANDLE h1, h2;
889     BY_HANDLE_FILE_INFORMATION info;
890     DWORD count;
891     BOOL ret = FALSE;
892     char buffer[2048];
893
894     if (!source || !dest)
895     {
896         SetLastError(ERROR_INVALID_PARAMETER);
897         return FALSE;
898     }
899
900     TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
901
902     if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
903                      NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
904     {
905         WARN("Unable to open source %s\n", debugstr_w(source));
906         return FALSE;
907     }
908
909     if (!GetFileInformationByHandle( h1, &info ))
910     {
911         WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
912         CloseHandle( h1 );
913         return FALSE;
914     }
915
916     if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
917                              fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
918                              info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
919     {
920         WARN("Unable to open dest %s\n", debugstr_w(dest));
921         CloseHandle( h1 );
922         return FALSE;
923     }
924
925     while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
926     {
927         char *p = buffer;
928         while (count != 0)
929         {
930             DWORD res;
931             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
932             p += res;
933             count -= res;
934         }
935     }
936     ret =  TRUE;
937 done:
938     CloseHandle( h1 );
939     CloseHandle( h2 );
940     return ret;
941 }
942
943
944 /**************************************************************************
945  *           CopyFileA   (KERNEL32.@)
946  */
947 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
948 {
949     UNICODE_STRING sourceW, destW;
950     BOOL ret;
951
952     if (!source || !dest)
953     {
954         SetLastError(ERROR_INVALID_PARAMETER);
955         return FALSE;
956     }
957
958     RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
959     RtlCreateUnicodeStringFromAsciiz(&destW, dest);
960
961     ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
962
963     RtlFreeUnicodeString(&sourceW);
964     RtlFreeUnicodeString(&destW);
965     return ret;
966 }
967
968
969 /**************************************************************************
970  *           CopyFileExW   (KERNEL32.@)
971  *
972  * This implementation ignores most of the extra parameters passed-in into
973  * the "ex" version of the method and calls the CopyFile method.
974  * It will have to be fixed eventually.
975  */
976 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
977                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
978                         LPBOOL cancelFlagPointer, DWORD copyFlags)
979 {
980     /*
981      * Interpret the only flag that CopyFile can interpret.
982      */
983     return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
984 }
985
986
987 /**************************************************************************
988  *           CopyFileExA   (KERNEL32.@)
989  */
990 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
991                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
992                         LPBOOL cancelFlagPointer, DWORD copyFlags)
993 {
994     UNICODE_STRING sourceW, destW;
995     BOOL ret;
996
997     if (!sourceFilename || !destFilename)
998     {
999         SetLastError(ERROR_INVALID_PARAMETER);
1000         return FALSE;
1001     }
1002
1003     RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
1004     RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
1005
1006     ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
1007                       cancelFlagPointer, copyFlags);
1008
1009     RtlFreeUnicodeString(&sourceW);
1010     RtlFreeUnicodeString(&destW);
1011     return ret;
1012 }