- start moving a few file related functions from files/file.c to
[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 <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 #endif
47 #ifdef HAVE_SYS_POLL_H
48 # include <sys/poll.h>
49 #endif
50 #include <time.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #ifdef HAVE_UTIME_H
55 # include <utime.h>
56 #endif
57
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "winerror.h"
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "wine/winbase16.h"
65 #include "wine/server.h"
66
67 #include "drive.h"
68 #include "file.h"
69 #include "async.h"
70 #include "heap.h"
71 #include "msdos.h"
72 #include "wincon.h"
73 #include "../kernel/kernel_private.h"
74
75 #include "smb.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
78
79 WINE_DEFAULT_DEBUG_CHANNEL(file);
80
81 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
82 #define MAP_ANON MAP_ANONYMOUS
83 #endif
84
85 /* Macro to derive file offset from OVERLAPPED struct */
86 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
87
88 HANDLE dos_handles[DOS_TABLE_SIZE];
89 mode_t FILE_umask;
90
91 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
92
93 /***********************************************************************
94  *                  Asynchronous file I/O                              *
95  */
96 static DWORD fileio_get_async_status (const async_private *ovp);
97 static DWORD fileio_get_async_count (const async_private *ovp);
98 static void fileio_set_async_status (async_private *ovp, const DWORD status);
99 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
100 static void fileio_async_cleanup (async_private *ovp);
101
102 static async_ops fileio_async_ops =
103 {
104     fileio_get_async_status,       /* get_status */
105     fileio_set_async_status,       /* set_status */
106     fileio_get_async_count,        /* get_count */
107     fileio_call_completion_func,   /* call_completion */
108     fileio_async_cleanup           /* cleanup */
109 };
110
111 static async_ops fileio_nocomp_async_ops =
112 {
113     fileio_get_async_status,       /* get_status */
114     fileio_set_async_status,       /* set_status */
115     fileio_get_async_count,        /* get_count */
116     NULL,                          /* call_completion */
117     fileio_async_cleanup           /* cleanup */
118 };
119
120 typedef struct async_fileio
121 {
122     struct async_private             async;
123     LPOVERLAPPED                     lpOverlapped;
124     LPOVERLAPPED_COMPLETION_ROUTINE  completion_func;
125     char                             *buffer;
126     unsigned int                     count;
127     enum fd_type                     fd_type;
128 } async_fileio;
129
130 static DWORD fileio_get_async_status (const struct async_private *ovp)
131 {
132     return ((async_fileio*) ovp)->lpOverlapped->Internal;
133 }
134
135 static void fileio_set_async_status (async_private *ovp, const DWORD status)
136 {
137     ((async_fileio*) ovp)->lpOverlapped->Internal = status;
138 }
139
140 static DWORD fileio_get_async_count (const struct async_private *ovp)
141 {
142     async_fileio *fileio = (async_fileio*) ovp;
143
144     if (fileio->count < fileio->lpOverlapped->InternalHigh)
145         return 0;
146     return fileio->count - fileio->lpOverlapped->InternalHigh;
147 }
148
149 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
150 {
151     async_fileio *ovp = (async_fileio*) data;
152     TRACE ("data: %p\n", ovp);
153
154     ovp->completion_func( RtlNtStatusToDosError ( ovp->lpOverlapped->Internal ),
155                           ovp->lpOverlapped->InternalHigh,
156                           ovp->lpOverlapped );
157
158     fileio_async_cleanup ( &ovp->async );
159 }
160
161 static void fileio_async_cleanup ( struct async_private *ovp )
162 {
163     HeapFree ( GetProcessHeap(), 0, ovp );
164 }
165
166 /***********************************************************************
167  *              FILE_ConvertOFMode
168  *
169  * Convert OF_* mode into flags for CreateFile.
170  */
171 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
172 {
173     switch(mode & 0x03)
174     {
175     case OF_READ:      *access = GENERIC_READ; break;
176     case OF_WRITE:     *access = GENERIC_WRITE; break;
177     case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
178     default:           *access = 0; break;
179     }
180     switch(mode & 0x70)
181     {
182     case OF_SHARE_EXCLUSIVE:  *sharing = 0; break;
183     case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
184     case OF_SHARE_DENY_READ:  *sharing = FILE_SHARE_WRITE; break;
185     case OF_SHARE_DENY_NONE:
186     case OF_SHARE_COMPAT:
187     default:                  *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
188     }
189 }
190
191
192 /***********************************************************************
193  *              FILE_strcasecmp
194  *
195  * locale-independent case conversion for file I/O
196  */
197 int FILE_strcasecmp( const char *str1, const char *str2 )
198 {
199     int ret = 0;
200     for ( ; ; str1++, str2++)
201         if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
202     return ret;
203 }
204
205
206 /***********************************************************************
207  *              FILE_strncasecmp
208  *
209  * locale-independent case conversion for file I/O
210  */
211 int FILE_strncasecmp( const char *str1, const char *str2, int len )
212 {
213     int ret = 0;
214     for ( ; len > 0; len--, str1++, str2++)
215         if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
216     return ret;
217 }
218
219
220 /***********************************************************************
221  *           FILE_GetNtStatus(void)
222  *
223  * Retrieve the Nt Status code from errno.
224  * Try to be consistent with FILE_SetDosError().
225  */
226 DWORD FILE_GetNtStatus(void)
227 {
228     int err = errno;
229     DWORD nt;
230     TRACE ( "errno = %d\n", errno );
231     switch ( err )
232     {
233     case EAGAIN:       nt = STATUS_SHARING_VIOLATION;       break;
234     case EBADF:        nt = STATUS_INVALID_HANDLE;          break;
235     case ENOSPC:       nt = STATUS_DISK_FULL;               break;
236     case EPERM:
237     case EROFS:
238     case EACCES:       nt = STATUS_ACCESS_DENIED;           break;
239     case ENOENT:       nt = STATUS_SHARING_VIOLATION;       break;
240     case EISDIR:       nt = STATUS_FILE_IS_A_DIRECTORY;     break;
241     case EMFILE:
242     case ENFILE:       nt = STATUS_NO_MORE_FILES;           break;
243     case EINVAL:
244     case ENOTEMPTY:    nt = STATUS_DIRECTORY_NOT_EMPTY;     break;
245     case EPIPE:        nt = STATUS_PIPE_BROKEN;             break;
246     case ENOEXEC:      /* ?? */
247     case ESPIPE:       /* ?? */
248     case EEXIST:       /* ?? */
249     default:
250         FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
251         nt = STATUS_UNSUCCESSFUL;
252     }
253     return nt;
254 }
255
256 /***********************************************************************
257  *           FILE_SetDosError
258  *
259  * Set the DOS error code from errno.
260  */
261 void FILE_SetDosError(void)
262 {
263     int save_errno = errno; /* errno gets overwritten by printf */
264
265     TRACE("errno = %d %s\n", errno, strerror(errno));
266     switch (save_errno)
267     {
268     case EAGAIN:
269         SetLastError( ERROR_SHARING_VIOLATION );
270         break;
271     case EBADF:
272         SetLastError( ERROR_INVALID_HANDLE );
273         break;
274     case ENOSPC:
275         SetLastError( ERROR_HANDLE_DISK_FULL );
276         break;
277     case EACCES:
278     case EPERM:
279     case EROFS:
280         SetLastError( ERROR_ACCESS_DENIED );
281         break;
282     case EBUSY:
283         SetLastError( ERROR_LOCK_VIOLATION );
284         break;
285     case ENOENT:
286         SetLastError( ERROR_FILE_NOT_FOUND );
287         break;
288     case EISDIR:
289         SetLastError( ERROR_CANNOT_MAKE );
290         break;
291     case ENFILE:
292     case EMFILE:
293         SetLastError( ERROR_NO_MORE_FILES );
294         break;
295     case EEXIST:
296         SetLastError( ERROR_FILE_EXISTS );
297         break;
298     case EINVAL:
299     case ESPIPE:
300         SetLastError( ERROR_SEEK );
301         break;
302     case ENOTEMPTY:
303         SetLastError( ERROR_DIR_NOT_EMPTY );
304         break;
305     case ENOEXEC:
306         SetLastError( ERROR_BAD_FORMAT );
307         break;
308     default:
309         WARN("unknown file error: %s\n", strerror(save_errno) );
310         SetLastError( ERROR_GEN_FAILURE );
311         break;
312     }
313     errno = save_errno;
314 }
315
316
317 /***********************************************************************
318  *           FILE_GetUnixHandleType
319  *
320  * Retrieve the Unix handle corresponding to a file handle.
321  * Returns -1 on failure.
322  */
323 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
324 {
325     int ret, flags, fd = -1;
326
327     ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
328     if (flags_ptr) *flags_ptr = flags;
329     if (ret) SetLastError( RtlNtStatusToDosError(ret) );
330     else if (((access & GENERIC_READ)  && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
331              ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
332     {
333         close (fd);
334         SetLastError ( ERROR_PIPE_NOT_CONNECTED );
335         return -1;
336     }
337     return fd;
338 }
339
340 /***********************************************************************
341  *           FILE_GetUnixHandle
342  *
343  * Retrieve the Unix handle corresponding to a file handle.
344  * Returns -1 on failure.
345  */
346 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
347 {
348     return FILE_GetUnixHandleType( handle, access, NULL, NULL );
349 }
350
351 /******************************************************************
352  *              OpenConsoleW            (KERNEL32.@)
353  *
354  * Undocumented
355  *      Open a handle to the current process console.
356  *      Returns INVALID_HANDLE_VALUE on failure.
357  */
358 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
359                            DWORD creation)
360 {
361     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
362     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
363     BOOL        output;
364     HANDLE ret;
365
366     if (strcmpW(coninW, name) == 0) 
367         output = FALSE;
368     else if (strcmpW(conoutW, name) == 0) 
369         output = TRUE;
370     else
371     {
372         SetLastError(ERROR_INVALID_NAME);
373         return INVALID_HANDLE_VALUE;
374     }
375     if (creation != OPEN_EXISTING)
376     {
377         SetLastError(ERROR_INVALID_PARAMETER);
378         return INVALID_HANDLE_VALUE;
379     }
380
381     SERVER_START_REQ( open_console )
382     {
383         req->from    = output;
384         req->access  = access;
385         req->share   = FILE_SHARE_READ | FILE_SHARE_WRITE;
386         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
387         SetLastError(0);
388         wine_server_call_err( req );
389         ret = reply->handle;
390     }
391     SERVER_END_REQ;
392     return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
393 }
394
395 /******************************************************************
396  *              VerifyConsoleIoHandle            (KERNEL32.@)
397  *
398  * Undocumented
399  */
400 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
401 {
402     BOOL ret;
403
404     if (!is_console_handle(handle)) return FALSE;
405     SERVER_START_REQ(get_console_mode)
406     {
407         req->handle = console_handle_unmap(handle);
408         ret = !wine_server_call_err( req );
409     }
410     SERVER_END_REQ;
411     return ret;
412 }
413
414 /******************************************************************
415  *              DuplicateConsoleHandle            (KERNEL32.@)
416  *
417  * Undocumented
418  */
419 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
420                                      DWORD options)
421 {
422     HANDLE      ret;
423
424     if (!is_console_handle(handle) ||
425         !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle), 
426                          GetCurrentProcess(), &ret, access, inherit, options))
427         return INVALID_HANDLE_VALUE;
428     return console_handle_map(ret);
429 }
430
431 /******************************************************************
432  *              CloseConsoleHandle            (KERNEL32.@)
433  *
434  * Undocumented
435  */
436 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
437 {
438     if (!is_console_handle(handle)) 
439     {
440         SetLastError(ERROR_INVALID_PARAMETER);
441         return FALSE;
442     }
443     return CloseHandle(console_handle_unmap(handle));
444 }
445
446 /******************************************************************
447  *              GetConsoleInputWaitHandle            (KERNEL32.@)
448  *
449  * Undocumented
450  */
451 HANDLE WINAPI GetConsoleInputWaitHandle(void)
452 {
453     static HANDLE console_wait_event;
454  
455     /* FIXME: this is not thread safe */
456     if (!console_wait_event)
457     {
458         SERVER_START_REQ(get_console_wait_event)
459         {
460             if (!wine_server_call_err( req )) console_wait_event = reply->handle;
461         }
462         SERVER_END_REQ;
463     }
464     return console_wait_event;
465 }
466 /* end of FIXME */
467
468
469 /* FIXME: those routines defined as pointers are needed, because this file is
470  * currently compiled into NTDLL whereas it belongs to kernel32.
471  * this shall go away once all the DLL separation process is done
472  */
473 typedef BOOL    (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
474
475 static  BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
476 {
477     static      HANDLE  hKernel /* = 0 */;
478     static      pRW     pReadConsole  /* = 0 */;
479
480     if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
481         (!pReadConsole &&
482          !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
483     {
484         *nr = 0;
485         return 0;
486     }
487     return (pReadConsole)(hCon, buf, nb, nr, p);
488 }
489
490 static  BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
491 {
492     static      HANDLE  hKernel /* = 0 */;
493     static      pRW     pWriteConsole  /* = 0 */;
494
495     if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
496         (!pWriteConsole &&
497          !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
498     {
499         *nr = 0;
500         return 0;
501     }
502     return (pWriteConsole)(hCon, buf, nb, nr, p);
503 }
504 /* end of FIXME */
505
506 /***********************************************************************
507  *           FILE_CreateFile
508  *
509  * Implementation of CreateFile. Takes a Unix path name.
510  * Returns 0 on failure.
511  */
512 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
513                         LPSECURITY_ATTRIBUTES sa, DWORD creation,
514                         DWORD attributes, HANDLE template, BOOL fail_read_only,
515                         UINT drive_type )
516 {
517     unsigned int err;
518     HANDLE ret;
519
520     for (;;)
521     {
522         SERVER_START_REQ( create_file )
523         {
524             req->access     = access;
525             req->inherit    = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
526             req->sharing    = sharing;
527             req->create     = creation;
528             req->attrs      = attributes;
529             req->drive_type = drive_type;
530             wine_server_add_data( req, filename, strlen(filename) );
531             SetLastError(0);
532             err = wine_server_call( req );
533             ret = reply->handle;
534         }
535         SERVER_END_REQ;
536
537         /* If write access failed, retry without GENERIC_WRITE */
538
539         if (!ret && !fail_read_only && (access & GENERIC_WRITE))
540         {
541             if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
542             {
543                 TRACE("Write access failed for file '%s', trying without "
544                       "write access\n", filename);
545                 access &= ~GENERIC_WRITE;
546                 continue;
547             }
548         }
549
550         if (err)
551         {
552             /* In the case file creation was rejected due to CREATE_NEW flag
553              * was specified and file with that name already exists, correct
554              * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
555              * Note: RtlNtStatusToDosError is not the subject to blame here.
556              */
557             if (err == STATUS_OBJECT_NAME_COLLISION)
558                 SetLastError( ERROR_FILE_EXISTS );
559             else
560                 SetLastError( RtlNtStatusToDosError(err) );
561         }
562
563         if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
564         return ret;
565     }
566 }
567
568
569 /***********************************************************************
570  *           FILE_CreateDevice
571  *
572  * Same as FILE_CreateFile but for a device
573  * Returns 0 on failure.
574  */
575 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
576 {
577     HANDLE ret;
578     SERVER_START_REQ( create_device )
579     {
580         req->access  = access;
581         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
582         req->id      = client_id;
583         SetLastError(0);
584         wine_server_call_err( req );
585         ret = reply->handle;
586     }
587     SERVER_END_REQ;
588     return ret;
589 }
590
591 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
592 {
593     HANDLE ret;
594     DWORD len = 0;
595
596     if (name && (len = strlenW(name)) > MAX_PATH)
597     {
598         SetLastError( ERROR_FILENAME_EXCED_RANGE );
599         return 0;
600     }
601     SERVER_START_REQ( open_named_pipe )
602     {
603         req->access = access;
604         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
605         SetLastError(0);
606         wine_server_add_data( req, name, len * sizeof(WCHAR) );
607         wine_server_call_err( req );
608         ret = reply->handle;
609     }
610     SERVER_END_REQ;
611     TRACE("Returned %p\n",ret);
612     return ret;
613 }
614
615 /*************************************************************************
616  * CreateFileW [KERNEL32.@]  Creates or opens a file or other object
617  *
618  * Creates or opens an object, and returns a handle that can be used to
619  * access that object.
620  *
621  * PARAMS
622  *
623  * filename     [in] pointer to filename to be accessed
624  * access       [in] access mode requested
625  * sharing      [in] share mode
626  * sa           [in] pointer to security attributes
627  * creation     [in] how to create the file
628  * attributes   [in] attributes for newly created file
629  * template     [in] handle to file with extended attributes to copy
630  *
631  * RETURNS
632  *   Success: Open handle to specified file
633  *   Failure: INVALID_HANDLE_VALUE
634  *
635  * NOTES
636  *  Should call SetLastError() on failure.
637  *
638  * BUGS
639  *
640  * Doesn't support character devices, template files, or a
641  * lot of the 'attributes' flags yet.
642  */
643 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
644                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
645                               DWORD attributes, HANDLE template )
646 {
647     DOS_FULL_NAME full_name;
648     HANDLE ret;
649     static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
650     static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
651     static const WCHAR bkslashesW[] = {'\\','\\',0};
652     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
653     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
654
655     if (!filename)
656     {
657         SetLastError( ERROR_INVALID_PARAMETER );
658         return INVALID_HANDLE_VALUE;
659     }
660     TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
661           ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
662           ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
663           (!access)?"QUERY_ACCESS ":"",
664           ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
665           ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
666           ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
667           (creation ==CREATE_NEW)?"CREATE_NEW":
668           (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
669           (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
670           (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
671           (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
672
673     /* If the name starts with '\\?\', ignore the first 4 chars. */
674     if (!strncmpW(filename, bkslashes_with_question_markW, 4))
675     {
676         static const WCHAR uncW[] = {'U','N','C','\\',0};
677         filename += 4;
678         if (!strncmpiW(filename, uncW, 4))
679         {
680             FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
681             SetLastError( ERROR_PATH_NOT_FOUND );
682             return INVALID_HANDLE_VALUE;
683         }
684     }
685
686     if (!strncmpW(filename, bkslashes_with_dotW, 4))
687     {
688         static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
689         if(!strncmpiW(filename + 4, pipeW, 5))
690         {
691             TRACE("Opening a pipe: %s\n", debugstr_w(filename));
692             ret = FILE_OpenPipe( filename, access, sa );
693             goto done;
694         }
695         else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
696         {
697             ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa );
698             goto done;
699         }
700         else if (!DOSFS_GetDevice( filename ))
701         {
702             ret = DEVICE_Open( filename+4, access, sa );
703             goto done;
704         }
705         else
706                 filename+=4; /* fall into DOSFS_Device case below */
707     }
708
709     /* If the name still starts with '\\', it's a UNC name. */
710     if (!strncmpW(filename, bkslashesW, 2))
711     {
712         ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
713         goto done;
714     }
715
716     /* If the name contains a DOS wild card (* or ?), do no create a file */
717     if(strchrW(filename, '*') || strchrW(filename, '?'))
718     {
719         SetLastError(ERROR_BAD_PATHNAME);
720         return INVALID_HANDLE_VALUE;
721     }
722
723     /* Open a console for CONIN$ or CONOUT$ */
724     if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
725     {
726         ret = OpenConsoleW(filename, access, sa, creation);
727         goto done;
728     }
729
730     if (DOSFS_GetDevice( filename ))
731     {
732         TRACE("opening device %s\n", debugstr_w(filename) );
733
734         if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
735         {
736             /* Do not silence this please. It is a critical error. -MM */
737             ERR("Couldn't open device %s!\n", debugstr_w(filename));
738             SetLastError( ERROR_FILE_NOT_FOUND );
739         }
740         goto done;
741     }
742
743     /* check for filename, don't check for last entry if creating */
744     if (!DOSFS_GetFullName( filename,
745                             (creation == OPEN_EXISTING) ||
746                             (creation == TRUNCATE_EXISTING),
747                             &full_name )) {
748         WARN("Unable to get full filename from %s (GLE %ld)\n",
749              debugstr_w(filename), GetLastError());
750         return INVALID_HANDLE_VALUE;
751     }
752
753     ret = FILE_CreateFile( full_name.long_name, access, sharing,
754                            sa, creation, attributes, template,
755                            DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
756                            GetDriveTypeW( full_name.short_name ) );
757  done:
758     if (!ret) ret = INVALID_HANDLE_VALUE;
759     TRACE("returning %p\n", ret);
760     return ret;
761 }
762
763
764
765 /*************************************************************************
766  *              CreateFileA              (KERNEL32.@)
767  */
768 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
769                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
770                               DWORD attributes, HANDLE template)
771 {
772     UNICODE_STRING filenameW;
773     HANDLE ret = INVALID_HANDLE_VALUE;
774
775     if (!filename)
776     {
777         SetLastError( ERROR_INVALID_PARAMETER );
778         return INVALID_HANDLE_VALUE;
779     }
780
781     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
782     {
783         ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
784                           attributes, template);
785         RtlFreeUnicodeString(&filenameW);
786     }
787     else
788         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
789     return ret;
790 }
791
792
793 /***********************************************************************
794  *           FILE_FillInfo
795  *
796  * Fill a file information from a struct stat.
797  */
798 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
799 {
800     if (S_ISDIR(st->st_mode))
801         info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
802     else
803         info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
804     if (!(st->st_mode & S_IWUSR))
805         info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
806
807     RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
808     RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
809     RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
810
811     info->dwVolumeSerialNumber = 0;  /* FIXME */
812     info->nFileSizeHigh = 0;
813     info->nFileSizeLow  = 0;
814     if (!S_ISDIR(st->st_mode)) {
815         info->nFileSizeHigh = st->st_size >> 32;
816         info->nFileSizeLow  = st->st_size & 0xffffffff;
817     }
818     info->nNumberOfLinks = st->st_nlink;
819     info->nFileIndexHigh = 0;
820     info->nFileIndexLow  = st->st_ino;
821 }
822
823
824 /***********************************************************************
825  *           FILE_Stat
826  *
827  * Stat a Unix path name. Return TRUE if OK.
828  */
829 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
830 {
831     struct stat st;
832     int is_symlink;
833     LPCSTR p;
834
835     if (lstat( unixName, &st ) == -1)
836     {
837         FILE_SetDosError();
838         return FALSE;
839     }
840     is_symlink = S_ISLNK(st.st_mode);
841     if (is_symlink)
842     {
843         /* do a "real" stat to find out
844            about the type of the symlink destination */
845         if (stat( unixName, &st ) == -1)
846         {
847             FILE_SetDosError();
848             return FALSE;
849         }
850     }
851
852     /* fill in the information we gathered so far */
853     FILE_FillInfo( &st, info );
854
855     /* and now see if this is a hidden file, based on the name */
856     p = strrchr( unixName, '/');
857     p = p ? p + 1 : unixName;
858     if (*p == '.' && *(p+1)  && (*(p+1) != '.' || *(p+2)))
859     {
860         static const WCHAR wineW[] = {'w','i','n','e',0};
861         static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
862         static int show_dot_files = -1;
863         if (show_dot_files == -1)
864             show_dot_files = PROFILE_GetWineIniBool(wineW, ShowDotFilesW, 0);
865         if (!show_dot_files)
866             info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
867     }
868     if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
869     return TRUE;
870 }
871
872
873 /***********************************************************************
874  *             GetFileInformationByHandle   (KERNEL32.@)
875  */
876 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
877                                          BY_HANDLE_FILE_INFORMATION *info )
878 {
879     DWORD ret;
880     if (!info) return 0;
881
882     TRACE("%p\n", hFile);
883
884     SERVER_START_REQ( get_file_info )
885     {
886         req->handle = hFile;
887         if ((ret = !wine_server_call_err( req )))
888         {
889             /* FIXME: which file types are supported ?
890              * Serial ports (FILE_TYPE_CHAR) are not,
891              * and MSDN also says that pipes are not supported.
892              * FILE_TYPE_REMOTE seems to be supported according to
893              * MSDN q234741.txt */
894             if ((reply->type == FILE_TYPE_DISK) ||  (reply->type == FILE_TYPE_REMOTE))
895             {
896                 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
897                 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
898                 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
899                 info->dwFileAttributes     = reply->attr;
900                 info->dwVolumeSerialNumber = reply->serial;
901                 info->nFileSizeHigh        = reply->size_high;
902                 info->nFileSizeLow         = reply->size_low;
903                 info->nNumberOfLinks       = reply->links;
904                 info->nFileIndexHigh       = reply->index_high;
905                 info->nFileIndexLow        = reply->index_low;
906             }
907             else
908             {
909                 SetLastError(ERROR_NOT_SUPPORTED);
910                 ret = 0;
911             }
912         }
913     }
914     SERVER_END_REQ;
915     return ret;
916 }
917
918
919 /**************************************************************************
920  *           GetFileAttributesW   (KERNEL32.@)
921  */
922 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
923 {
924     DOS_FULL_NAME full_name;
925     BY_HANDLE_FILE_INFORMATION info;
926
927     if (name == NULL)
928     {
929         SetLastError( ERROR_INVALID_PARAMETER );
930         return -1;
931     }
932     if (!DOSFS_GetFullName( name, TRUE, &full_name) )
933         return -1;
934     if (!FILE_Stat( full_name.long_name, &info, NULL )) return -1;
935     return info.dwFileAttributes;
936 }
937
938
939 /**************************************************************************
940  *           GetFileAttributesA   (KERNEL32.@)
941  */
942 DWORD WINAPI GetFileAttributesA( LPCSTR name )
943 {
944     UNICODE_STRING nameW;
945     DWORD ret = (DWORD)-1;
946
947     if (!name)
948     {
949         SetLastError( ERROR_INVALID_PARAMETER );
950         return (DWORD)-1;
951     }
952
953     if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
954     {
955         ret = GetFileAttributesW(nameW.Buffer);
956         RtlFreeUnicodeString(&nameW);
957     }
958     else
959         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
960     return ret;
961 }
962
963
964 /**************************************************************************
965  *              SetFileAttributesW      (KERNEL32.@)
966  */
967 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
968 {
969     struct stat buf;
970     DOS_FULL_NAME full_name;
971
972     if (!lpFileName)
973     {
974         SetLastError( ERROR_INVALID_PARAMETER );
975         return FALSE;
976     }
977
978     TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
979
980     if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
981         return FALSE;
982
983     if(stat(full_name.long_name,&buf)==-1)
984     {
985         FILE_SetDosError();
986         return FALSE;
987     }
988     if (attributes & FILE_ATTRIBUTE_READONLY)
989     {
990         if(S_ISDIR(buf.st_mode))
991             /* FIXME */
992             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
993         else
994             buf.st_mode &= ~0222; /* octal!, clear write permission bits */
995         attributes &= ~FILE_ATTRIBUTE_READONLY;
996     }
997     else
998     {
999         /* add write permission */
1000         buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
1001     }
1002     if (attributes & FILE_ATTRIBUTE_DIRECTORY)
1003     {
1004         if (!S_ISDIR(buf.st_mode))
1005             FIXME("SetFileAttributes expected the file %s to be a directory\n",
1006                   debugstr_w(lpFileName));
1007         attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
1008     }
1009     attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
1010     if (attributes)
1011         FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
1012     if (-1==chmod(full_name.long_name,buf.st_mode))
1013     {
1014         if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
1015         {
1016            SetLastError( ERROR_ACCESS_DENIED );
1017            return FALSE;
1018         }
1019
1020         /*
1021         * FIXME: We don't return FALSE here because of differences between
1022         *        Linux and Windows privileges. Under Linux only the owner of
1023         *        the file is allowed to change file attributes. Under Windows,
1024         *        applications expect that if you can write to a file, you can also
1025         *        change its attributes (see GENERIC_WRITE). We could try to be
1026         *        clever here but that would break multi-user installations where
1027         *        users share read-only DLLs. This is because some installers like
1028         *        to change attributes of already installed DLLs.
1029         */
1030         FIXME("Couldn't set file attributes for existing file \"%s\".\n"
1031               "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
1032     }
1033     return TRUE;
1034 }
1035
1036
1037 /**************************************************************************
1038  *              SetFileAttributesA      (KERNEL32.@)
1039  */
1040 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
1041 {
1042     UNICODE_STRING filenameW;
1043     BOOL ret = FALSE;
1044
1045     if (!lpFileName)
1046     {
1047         SetLastError( ERROR_INVALID_PARAMETER );
1048         return FALSE;
1049     }
1050
1051     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
1052     {
1053         ret = SetFileAttributesW(filenameW.Buffer, attributes);
1054         RtlFreeUnicodeString(&filenameW);
1055     }
1056     else
1057         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1058     return ret;
1059 }
1060
1061
1062 /***********************************************************************
1063  *           GetFileTime   (KERNEL32.@)
1064  */
1065 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1066                            FILETIME *lpLastAccessTime,
1067                            FILETIME *lpLastWriteTime )
1068 {
1069     BY_HANDLE_FILE_INFORMATION info;
1070     if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
1071     if (lpCreationTime)   *lpCreationTime   = info.ftCreationTime;
1072     if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
1073     if (lpLastWriteTime)  *lpLastWriteTime  = info.ftLastWriteTime;
1074     return TRUE;
1075 }
1076
1077
1078 /***********************************************************************
1079  *           FILE_GetTempFileName : utility for GetTempFileName
1080  */
1081 static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique,
1082                                   LPWSTR buffer )
1083 {
1084     static UINT unique_temp;
1085     DOS_FULL_NAME full_name;
1086     int i;
1087     LPWSTR p;
1088     UINT num;
1089     char buf[20];
1090
1091     if ( !path || !prefix || !buffer )
1092     {
1093         SetLastError( ERROR_INVALID_PARAMETER );
1094         return 0;
1095     }
1096
1097     if (!unique_temp) unique_temp = time(NULL) & 0xffff;
1098     num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
1099
1100     strcpyW( buffer, path );
1101     p = buffer + strlenW(buffer);
1102
1103     /* add a \, if there isn't one and path is more than just the drive letter ... */
1104     if ( !((strlenW(buffer) == 2) && (buffer[1] == ':'))
1105         && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
1106
1107     for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1108
1109     sprintf( buf, "%04x.tmp", num );
1110     MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1111
1112     /* Now try to create it */
1113
1114     if (!unique)
1115     {
1116         do
1117         {
1118             HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1119                                          CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1120             if (handle != INVALID_HANDLE_VALUE)
1121             {  /* We created it */
1122                 TRACE("created %s\n", debugstr_w(buffer) );
1123                 CloseHandle( handle );
1124                 break;
1125             }
1126             if (GetLastError() != ERROR_FILE_EXISTS &&
1127                 GetLastError() != ERROR_SHARING_VIOLATION)
1128                 break;  /* No need to go on */
1129             num++;
1130             sprintf( buf, "%04x.tmp", num );
1131             MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20);
1132         } while (num != (unique & 0xffff));
1133     }
1134
1135     /* Get the full path name */
1136
1137     if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
1138     {
1139         char *slash;
1140         /* Check if we have write access in the directory */
1141         if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
1142         if (access( full_name.long_name, W_OK ) == -1)
1143             WARN("returns %s, which doesn't seem to be writeable.\n",
1144                   debugstr_w(buffer) );
1145     }
1146     TRACE("returning %s\n", debugstr_w(buffer) );
1147     return unique ? unique : num;
1148 }
1149
1150
1151 /***********************************************************************
1152  *           GetTempFileNameA   (KERNEL32.@)
1153  */
1154 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1155                                   LPSTR buffer)
1156 {
1157     UNICODE_STRING pathW, prefixW;
1158     WCHAR bufferW[MAX_PATH];
1159     UINT ret;
1160
1161     if ( !path || !prefix || !buffer )
1162     {
1163         SetLastError( ERROR_INVALID_PARAMETER );
1164         return 0;
1165     }
1166
1167     RtlCreateUnicodeStringFromAsciiz(&pathW, path);
1168     RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
1169
1170     ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
1171     if (ret)
1172         WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
1173
1174     RtlFreeUnicodeString(&pathW);
1175     RtlFreeUnicodeString(&prefixW);
1176     return ret;
1177 }
1178
1179 /***********************************************************************
1180  *           GetTempFileNameW   (KERNEL32.@)
1181  */
1182 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1183                                   LPWSTR buffer )
1184 {
1185     return FILE_GetTempFileName( path, prefix, unique, buffer );
1186 }
1187
1188
1189 /***********************************************************************
1190  *           FILE_DoOpenFile
1191  *
1192  * Implementation of OpenFile16() and OpenFile32().
1193  */
1194 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
1195 {
1196     HFILE hFileRet;
1197     HANDLE handle;
1198     FILETIME filetime;
1199     WORD filedatetime[2];
1200     DOS_FULL_NAME full_name;
1201     DWORD access, sharing;
1202     WCHAR *p;
1203     WCHAR buffer[MAX_PATH];
1204     LPWSTR nameW;
1205
1206     if (!ofs) return HFILE_ERROR;
1207
1208     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1209           ((mode & 0x3 )==OF_READ)?"OF_READ":
1210           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1211           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1212           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1213           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1214           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1215           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1216           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1217           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1218           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1219           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1220           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1221           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1222           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1223           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1224           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1225           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1226           );
1227
1228
1229     ofs->cBytes = sizeof(OFSTRUCT);
1230     ofs->nErrCode = 0;
1231     if (mode & OF_REOPEN) name = ofs->szPathName;
1232
1233     if (!name) {
1234         ERR("called with `name' set to NULL ! Please debug.\n");
1235         return HFILE_ERROR;
1236     }
1237
1238     TRACE("%s %04x\n", name, mode );
1239
1240     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1241        Are there any cases where getting the path here is wrong?
1242        Uwe Bonnes 1997 Apr 2 */
1243     if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1244                              ofs->szPathName, NULL )) goto error;
1245     FILE_ConvertOFMode( mode, &access, &sharing );
1246
1247     /* OF_PARSE simply fills the structure */
1248
1249     if (mode & OF_PARSE)
1250     {
1251         ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1252                            != DRIVE_REMOVABLE);
1253         TRACE("(%s): OF_PARSE, res = '%s'\n",
1254                       name, ofs->szPathName );
1255         return 0;
1256     }
1257
1258     /* OF_CREATE is completely different from all other options, so
1259        handle it first */
1260
1261     if (mode & OF_CREATE)
1262     {
1263         if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1264                                    sharing, NULL, CREATE_ALWAYS,
1265                                    FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1266             goto error;
1267         goto success;
1268     }
1269
1270     MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1271     nameW = buffer;
1272
1273     /* If OF_SEARCH is set, ignore the given path */
1274
1275     if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1276     {
1277         /* First try the file name as is */
1278         if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1279         /* Now remove the path */
1280         if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1281         if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1282         if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1283         if (!nameW[0]) goto not_found;
1284     }
1285
1286     /* Now look for the file */
1287
1288     if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1289
1290 found:
1291     TRACE("found %s = %s\n",
1292           full_name.long_name, debugstr_w(full_name.short_name) );
1293     WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1294                         ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1295
1296     if (mode & OF_SHARE_EXCLUSIVE)
1297       /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1298          on the file <tempdir>/_ins0432._mp to determine how
1299          far installation has proceeded.
1300          _ins0432._mp is an executable and while running the
1301          application expects the open with OF_SHARE_ to fail*/
1302       /* Probable FIXME:
1303          As our loader closes the files after loading the executable,
1304          we can't find the running executable with FILE_InUse.
1305          The loader should keep the file open, as Windows does that, too.
1306        */
1307       {
1308         char *last = strrchr(full_name.long_name,'/');
1309         if (!last)
1310           last = full_name.long_name - 1;
1311         if (GetModuleHandle16(last+1))
1312           {
1313             TRACE("Denying shared open for %s\n",full_name.long_name);
1314             return HFILE_ERROR;
1315           }
1316       }
1317
1318     if (mode & OF_DELETE)
1319     {
1320         if (unlink( full_name.long_name ) == -1) goto not_found;
1321         TRACE("(%s): OF_DELETE return = OK\n", name);
1322         return 1;
1323     }
1324
1325     handle = FILE_CreateFile( full_name.long_name, access, sharing,
1326                                 NULL, OPEN_EXISTING, 0, 0,
1327                                 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1328                                 GetDriveTypeW( full_name.short_name ) );
1329     if (!handle) goto not_found;
1330
1331     GetFileTime( handle, NULL, NULL, &filetime );
1332     FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1333     if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1334     {
1335         if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1336         {
1337             CloseHandle( handle );
1338             WARN("(%s): OF_VERIFY failed\n", name );
1339             /* FIXME: what error here? */
1340             SetLastError( ERROR_FILE_NOT_FOUND );
1341             goto error;
1342         }
1343     }
1344     ofs->Reserved1 = filedatetime[0];
1345     ofs->Reserved2 = filedatetime[1];
1346
1347 success:  /* We get here if the open was successful */
1348     TRACE("(%s): OK, return = %p\n", name, handle );
1349     if (win32)
1350     {
1351         hFileRet = (HFILE)handle;
1352         if (mode & OF_EXIST) /* Return the handle, but close it first */
1353             CloseHandle( handle );
1354     }
1355     else
1356     {
1357         hFileRet = Win32HandleToDosFileHandle( handle );
1358         if (hFileRet == HFILE_ERROR16) goto error;
1359         if (mode & OF_EXIST) /* Return the handle, but close it first */
1360             _lclose16( hFileRet );
1361     }
1362     return hFileRet;
1363
1364 not_found:  /* We get here if the file does not exist */
1365     WARN("'%s' not found or sharing violation\n", name );
1366     SetLastError( ERROR_FILE_NOT_FOUND );
1367     /* fall through */
1368
1369 error:  /* We get here if there was an error opening the file */
1370     ofs->nErrCode = GetLastError();
1371     WARN("(%s): return = HFILE_ERROR error= %d\n",
1372                   name,ofs->nErrCode );
1373     return HFILE_ERROR;
1374 }
1375
1376
1377 /***********************************************************************
1378  *           OpenFile   (KERNEL.74)
1379  *           OpenFileEx (KERNEL.360)
1380  */
1381 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1382 {
1383     return FILE_DoOpenFile( name, ofs, mode, FALSE );
1384 }
1385
1386
1387 /***********************************************************************
1388  *           OpenFile   (KERNEL32.@)
1389  */
1390 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1391 {
1392     return FILE_DoOpenFile( name, ofs, mode, TRUE );
1393 }
1394
1395
1396 /***********************************************************************
1397  *           FILE_InitProcessDosHandles
1398  *
1399  * Allocates the default DOS handles for a process. Called either by
1400  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1401  */
1402 static void FILE_InitProcessDosHandles( void )
1403 {
1404     HANDLE cp = GetCurrentProcess();
1405     DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1406                     0, TRUE, DUPLICATE_SAME_ACCESS);
1407     DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1408                     0, TRUE, DUPLICATE_SAME_ACCESS);
1409     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1410                     0, TRUE, DUPLICATE_SAME_ACCESS);
1411     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1412                     0, TRUE, DUPLICATE_SAME_ACCESS);
1413     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1414                     0, TRUE, DUPLICATE_SAME_ACCESS);
1415 }
1416
1417 /***********************************************************************
1418  *           Win32HandleToDosFileHandle   (KERNEL32.21)
1419  *
1420  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1421  * longer valid after this function (even on failure).
1422  *
1423  * Note: this is not exactly right, since on Win95 the Win32 handles
1424  *       are on top of DOS handles and we do it the other way
1425  *       around. Should be good enough though.
1426  */
1427 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1428 {
1429     int i;
1430
1431     if (!handle || (handle == INVALID_HANDLE_VALUE))
1432         return HFILE_ERROR;
1433
1434     for (i = 5; i < DOS_TABLE_SIZE; i++)
1435         if (!dos_handles[i])
1436         {
1437             dos_handles[i] = handle;
1438             TRACE("Got %d for h32 %p\n", i, handle );
1439             return (HFILE)i;
1440         }
1441     CloseHandle( handle );
1442     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1443     return HFILE_ERROR;
1444 }
1445
1446
1447 /***********************************************************************
1448  *           DosFileHandleToWin32Handle   (KERNEL32.20)
1449  *
1450  * Return the Win32 handle for a DOS handle.
1451  *
1452  * Note: this is not exactly right, since on Win95 the Win32 handles
1453  *       are on top of DOS handles and we do it the other way
1454  *       around. Should be good enough though.
1455  */
1456 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1457 {
1458     HFILE16 hfile = (HFILE16)handle;
1459     if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1460     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1461     {
1462         SetLastError( ERROR_INVALID_HANDLE );
1463         return INVALID_HANDLE_VALUE;
1464     }
1465     return dos_handles[hfile];
1466 }
1467
1468
1469 /***********************************************************************
1470  *           DisposeLZ32Handle   (KERNEL32.22)
1471  *
1472  * Note: this is not entirely correct, we should only close the
1473  *       32-bit handle and not the 16-bit one, but we cannot do
1474  *       this because of the way our DOS handles are implemented.
1475  *       It shouldn't break anything though.
1476  */
1477 void WINAPI DisposeLZ32Handle( HANDLE handle )
1478 {
1479     int i;
1480
1481     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1482
1483     for (i = 5; i < DOS_TABLE_SIZE; i++)
1484         if (dos_handles[i] == handle)
1485         {
1486             dos_handles[i] = 0;
1487             CloseHandle( handle );
1488             break;
1489         }
1490 }
1491
1492
1493 /***********************************************************************
1494  *           FILE_Dup2
1495  *
1496  * dup2() function for DOS handles.
1497  */
1498 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1499 {
1500     HANDLE new_handle;
1501
1502     if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1503
1504     if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1505     {
1506         SetLastError( ERROR_INVALID_HANDLE );
1507         return HFILE_ERROR16;
1508     }
1509     if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1510                           GetCurrentProcess(), &new_handle,
1511                           0, FALSE, DUPLICATE_SAME_ACCESS ))
1512         return HFILE_ERROR16;
1513     if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1514     dos_handles[hFile2] = new_handle;
1515     return hFile2;
1516 }
1517
1518
1519 /***********************************************************************
1520  *           _lclose   (KERNEL.81)
1521  */
1522 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1523 {
1524     if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1525     {
1526         SetLastError( ERROR_INVALID_HANDLE );
1527         return HFILE_ERROR16;
1528     }
1529     TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1530     CloseHandle( dos_handles[hFile] );
1531     dos_handles[hFile] = 0;
1532     return 0;
1533 }
1534
1535
1536 /***********************************************************************
1537  *              GetOverlappedResult     (KERNEL32.@)
1538  *
1539  * Check the result of an Asynchronous data transfer from a file.
1540  *
1541  * RETURNS
1542  *   TRUE on success
1543  *   FALSE on failure
1544  *
1545  *  If successful (and relevant) lpTransferred will hold the number of
1546  *   bytes transferred during the async operation.
1547  *
1548  * BUGS
1549  *
1550  * Currently only works for WaitCommEvent, ReadFile, WriteFile
1551  *   with communications ports.
1552  *
1553  */
1554 BOOL WINAPI GetOverlappedResult(
1555     HANDLE hFile,              /* [in] handle of file to check on */
1556     LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped  */
1557     LPDWORD lpTransferred,     /* [in/out] number of bytes transferred  */
1558     BOOL bWait                 /* [in] wait for the transfer to complete ? */
1559 ) {
1560     DWORD r;
1561
1562     TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1563
1564     if(lpOverlapped==NULL)
1565     {
1566         ERR("lpOverlapped was null\n");
1567         return FALSE;
1568     }
1569     if(!lpOverlapped->hEvent)
1570     {
1571         ERR("lpOverlapped->hEvent was null\n");
1572         return FALSE;
1573     }
1574
1575     if ( bWait )
1576     {
1577         do {
1578             TRACE("waiting on %p\n",lpOverlapped);
1579             r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
1580             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1581         } while (r==STATUS_USER_APC);
1582     }
1583     else if ( lpOverlapped->Internal == STATUS_PENDING )
1584     {
1585         /* Wait in order to give APCs a chance to run. */
1586         /* This is cheating, so we must set the event again in case of success -
1587            it may be a non-manual reset event. */
1588         do {
1589             TRACE("waiting on %p\n",lpOverlapped);
1590             r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
1591             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1592         } while (r==STATUS_USER_APC);
1593         if ( r == WAIT_OBJECT_0 )
1594             NtSetEvent ( lpOverlapped->hEvent, NULL );
1595     }
1596
1597     if(lpTransferred)
1598         *lpTransferred = lpOverlapped->InternalHigh;
1599
1600     switch ( lpOverlapped->Internal )
1601     {
1602     case STATUS_SUCCESS:
1603         return TRUE;
1604     case STATUS_PENDING:
1605         SetLastError ( ERROR_IO_INCOMPLETE );
1606         if ( bWait ) ERR ("PENDING status after waiting!\n");
1607         return FALSE;
1608     default:
1609         SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1610         return FALSE;
1611     }
1612 }
1613
1614 /***********************************************************************
1615  *             CancelIo                   (KERNEL32.@)
1616  */
1617 BOOL WINAPI CancelIo(HANDLE handle)
1618 {
1619     async_private *ovp,*t;
1620
1621     TRACE("handle = %p\n",handle);
1622
1623     for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1624     {
1625         t = ovp->next;
1626         if ( ovp->handle == handle )
1627              cancel_async ( ovp );
1628     }
1629     WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1630     return TRUE;
1631 }
1632
1633 /***********************************************************************
1634  *             FILE_AsyncReadService      (INTERNAL)
1635  *
1636  *  This function is called while the client is waiting on the
1637  *  server, so we can't make any server calls here.
1638  */
1639 static void FILE_AsyncReadService(async_private *ovp)
1640 {
1641     async_fileio *fileio = (async_fileio*) ovp;
1642     LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1643     int result, r;
1644     int already = lpOverlapped->InternalHigh;
1645
1646     TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1647
1648     /* check to see if the data is ready (non-blocking) */
1649
1650     if ( fileio->fd_type == FD_TYPE_SOCKET )
1651         result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1652     else
1653     {
1654         result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1655                         OVERLAPPED_OFFSET (lpOverlapped) + already);
1656         if ((result < 0) && (errno == ESPIPE))
1657             result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1658     }
1659
1660     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1661     {
1662         TRACE("Deferred read %d\n",errno);
1663         r = STATUS_PENDING;
1664         goto async_end;
1665     }
1666
1667     /* check to see if the transfer is complete */
1668     if(result<0)
1669     {
1670         r = FILE_GetNtStatus ();
1671         goto async_end;
1672     }
1673     else if ( result == 0 )
1674     {
1675         r = ( lpOverlapped->InternalHigh ? STATUS_SUCCESS : STATUS_END_OF_FILE );
1676         goto async_end;
1677     }
1678
1679     lpOverlapped->InternalHigh += result;
1680     TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1681
1682     if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1683         r = STATUS_SUCCESS;
1684     else
1685         r = STATUS_PENDING;
1686
1687 async_end:
1688     lpOverlapped->Internal = r;
1689 }
1690
1691 /***********************************************************************
1692  *              FILE_ReadFileEx                (INTERNAL)
1693  */
1694 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1695                          LPOVERLAPPED overlapped,
1696                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1697                          HANDLE hEvent)
1698 {
1699     async_fileio *ovp;
1700     int fd;
1701     int flags;
1702     enum fd_type type;
1703
1704     TRACE("file %p to buf %p num %ld %p func %p\n",
1705           hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1706
1707     /* check that there is an overlapped struct */
1708     if (overlapped==NULL)
1709     {
1710         SetLastError(ERROR_INVALID_PARAMETER);
1711         return FALSE;
1712     }
1713
1714     fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1715     if ( fd < 0 )
1716     {
1717         WARN ( "Couldn't get FD\n" );
1718         return FALSE;
1719     }
1720
1721     ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1722     if(!ovp)
1723     {
1724         TRACE("HeapAlloc Failed\n");
1725         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1726         goto error;
1727     }
1728
1729     ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1730     ovp->async.handle = hFile;
1731     ovp->async.fd = fd;
1732     ovp->async.type = ASYNC_TYPE_READ;
1733     ovp->async.func = FILE_AsyncReadService;
1734     ovp->async.event = hEvent;
1735     ovp->lpOverlapped = overlapped;
1736     ovp->count = bytesToRead;
1737     ovp->completion_func = lpCompletionRoutine;
1738     ovp->buffer = buffer;
1739     ovp->fd_type = type;
1740
1741     return !register_new_async (&ovp->async);
1742
1743 error:
1744     close (fd);
1745     return FALSE;
1746
1747 }
1748
1749 /***********************************************************************
1750  *              ReadFileEx                (KERNEL32.@)
1751  */
1752 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1753                          LPOVERLAPPED overlapped,
1754                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1755 {
1756     overlapped->InternalHigh = 0;
1757     return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1758 }
1759
1760 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1761 {
1762     OVERLAPPED ov;
1763     BOOL r = FALSE;
1764
1765     TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1766
1767     ZeroMemory(&ov, sizeof (OVERLAPPED));
1768     if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1769     {
1770         if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1771         {
1772             r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1773         }
1774     }
1775     CloseHandle(ov.hEvent);
1776     return r;
1777 }
1778
1779 /***********************************************************************
1780  *              ReadFile                (KERNEL32.@)
1781  */
1782 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1783                         LPDWORD bytesRead, LPOVERLAPPED overlapped )
1784 {
1785     int unix_handle, result, flags;
1786     enum fd_type type;
1787
1788     TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1789           bytesRead, overlapped );
1790
1791     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
1792     if (!bytesToRead) return TRUE;
1793
1794     if (is_console_handle(hFile))
1795         return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1796
1797     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1798
1799     if (flags & FD_FLAG_OVERLAPPED)
1800     {
1801         if (unix_handle == -1) return FALSE;
1802         if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1803         {
1804             TRACE("Overlapped not specified or invalid event flag\n");
1805             close(unix_handle);
1806             SetLastError(ERROR_INVALID_PARAMETER);
1807             return FALSE;
1808         }
1809
1810         close(unix_handle);
1811         overlapped->InternalHigh = 0;
1812
1813         if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1814             return FALSE;
1815
1816         if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1817         {
1818             if ( GetLastError() == ERROR_IO_INCOMPLETE )
1819                 SetLastError ( ERROR_IO_PENDING );
1820             return FALSE;
1821         }
1822
1823         return TRUE;
1824     }
1825     if (flags & FD_FLAG_TIMEOUT)
1826     {
1827         close(unix_handle);
1828         return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1829     }
1830     switch(type)
1831     {
1832     case FD_TYPE_SMB:
1833         return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1834
1835     case FD_TYPE_DEFAULT:
1836         /* normal unix files */
1837         if (unix_handle == -1) return FALSE;
1838         if (overlapped)
1839         {
1840             DWORD highOffset = overlapped->OffsetHigh;
1841             if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1842                                                              &highOffset, FILE_BEGIN)) &&
1843                  (GetLastError() != NO_ERROR) )
1844             {
1845               close(unix_handle);
1846               return FALSE;
1847             }
1848         }
1849         break;
1850
1851     default:
1852         if (unix_handle == -1)
1853             return FALSE;
1854     }
1855
1856     if(overlapped)
1857     {
1858         off_t offset = OVERLAPPED_OFFSET(overlapped);
1859         if(lseek(unix_handle, offset, SEEK_SET) == -1)
1860         {
1861             close(unix_handle);
1862             SetLastError(ERROR_INVALID_PARAMETER);
1863             return FALSE;
1864         }
1865     }
1866
1867     /* code for synchronous reads */
1868     while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1869     {
1870         if ((errno == EAGAIN) || (errno == EINTR)) continue;
1871         if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1872         FILE_SetDosError();
1873         break;
1874     }
1875     close( unix_handle );
1876     if (result == -1) return FALSE;
1877     if (bytesRead) *bytesRead = result;
1878     return TRUE;
1879 }
1880
1881
1882 /***********************************************************************
1883  *             FILE_AsyncWriteService      (INTERNAL)
1884  *
1885  *  This function is called while the client is waiting on the
1886  *  server, so we can't make any server calls here.
1887  */
1888 static void FILE_AsyncWriteService(struct async_private *ovp)
1889 {
1890     async_fileio *fileio = (async_fileio *) ovp;
1891     LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1892     int result, r;
1893     int already = lpOverlapped->InternalHigh;
1894
1895     TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1896
1897     /* write some data (non-blocking) */
1898
1899     if ( fileio->fd_type == FD_TYPE_SOCKET )
1900         result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1901     else
1902     {
1903         result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1904                     OVERLAPPED_OFFSET (lpOverlapped) + already);
1905         if ((result < 0) && (errno == ESPIPE))
1906             result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1907     }
1908
1909     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1910     {
1911         r = STATUS_PENDING;
1912         goto async_end;
1913     }
1914
1915     /* check to see if the transfer is complete */
1916     if(result<0)
1917     {
1918         r = FILE_GetNtStatus ();
1919         goto async_end;
1920     }
1921
1922     lpOverlapped->InternalHigh += result;
1923
1924     TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1925
1926     if(lpOverlapped->InternalHigh < fileio->count)
1927         r = STATUS_PENDING;
1928     else
1929         r = STATUS_SUCCESS;
1930
1931 async_end:
1932     lpOverlapped->Internal = r;
1933 }
1934
1935 /***********************************************************************
1936  *              FILE_WriteFileEx
1937  */
1938 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1939                              LPOVERLAPPED overlapped,
1940                              LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1941                              HANDLE hEvent)
1942 {
1943     async_fileio *ovp;
1944     int fd;
1945     int flags;
1946     enum fd_type type;
1947
1948     TRACE("file %p to buf %p num %ld %p func %p handle %p\n",
1949           hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1950
1951     if (overlapped == NULL)
1952     {
1953         SetLastError(ERROR_INVALID_PARAMETER);
1954         return FALSE;
1955     }
1956
1957     fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1958     if ( fd < 0 )
1959     {
1960         TRACE( "Couldn't get FD\n" );
1961         return FALSE;
1962     }
1963
1964     ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1965     if(!ovp)
1966     {
1967         TRACE("HeapAlloc Failed\n");
1968         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1969         goto error;
1970     }
1971
1972     ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1973     ovp->async.handle = hFile;
1974     ovp->async.fd = fd;
1975     ovp->async.type = ASYNC_TYPE_WRITE;
1976     ovp->async.func = FILE_AsyncWriteService;
1977     ovp->lpOverlapped = overlapped;
1978     ovp->async.event = hEvent;
1979     ovp->buffer = (LPVOID) buffer;
1980     ovp->count = bytesToWrite;
1981     ovp->completion_func = lpCompletionRoutine;
1982     ovp->fd_type = type;
1983
1984     return !register_new_async (&ovp->async);
1985
1986 error:
1987     close (fd);
1988     return FALSE;
1989 }
1990
1991 /***********************************************************************
1992  *              WriteFileEx                (KERNEL32.@)
1993  */
1994 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1995                          LPOVERLAPPED overlapped,
1996                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1997 {
1998     overlapped->InternalHigh = 0;
1999
2000     return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
2001 }
2002
2003 /***********************************************************************
2004  *             WriteFile               (KERNEL32.@)
2005  */
2006 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
2007                          LPDWORD bytesWritten, LPOVERLAPPED overlapped )
2008 {
2009     int unix_handle, result, flags;
2010     enum fd_type type;
2011
2012     TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite,
2013           bytesWritten, overlapped );
2014
2015     if (bytesWritten) *bytesWritten = 0;  /* Do this before anything else */
2016     if (!bytesToWrite) return TRUE;
2017
2018     if (is_console_handle(hFile))
2019         return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
2020
2021     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
2022
2023     if (flags & FD_FLAG_OVERLAPPED)
2024     {
2025         if (unix_handle == -1) return FALSE;
2026         if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
2027         {
2028             TRACE("Overlapped not specified or invalid event flag\n");
2029             close(unix_handle);
2030             SetLastError(ERROR_INVALID_PARAMETER);
2031             return FALSE;
2032         }
2033
2034         close(unix_handle);
2035         overlapped->InternalHigh = 0;
2036
2037         if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
2038             return FALSE;
2039
2040         if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
2041         {
2042             if ( GetLastError() == ERROR_IO_INCOMPLETE )
2043                 SetLastError ( ERROR_IO_PENDING );
2044             return FALSE;
2045         }
2046
2047         return TRUE;
2048     }
2049
2050     switch(type)
2051     {
2052     case FD_TYPE_DEFAULT:
2053         if (unix_handle == -1) return FALSE;
2054
2055         if(overlapped)
2056         {
2057             DWORD highOffset = overlapped->OffsetHigh;
2058             if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
2059                                                              &highOffset, FILE_BEGIN)) &&
2060                  (GetLastError() != NO_ERROR) )
2061             {
2062               close(unix_handle);
2063               return FALSE;
2064             }
2065         }
2066         break;
2067
2068     default:
2069         if (unix_handle == -1)
2070             return FALSE;
2071         if (overlapped)
2072         {
2073             close(unix_handle);
2074             SetLastError(ERROR_INVALID_PARAMETER);
2075             return FALSE;
2076         }
2077         break;
2078     }
2079
2080     if(overlapped)
2081     {
2082         off_t offset = OVERLAPPED_OFFSET(overlapped);
2083         if(lseek(unix_handle, offset, SEEK_SET) == -1)
2084         {
2085             close(unix_handle);
2086             SetLastError(ERROR_INVALID_PARAMETER);
2087             return FALSE;
2088         }
2089     }
2090
2091     /* synchronous file write */
2092     while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
2093     {
2094         if ((errno == EAGAIN) || (errno == EINTR)) continue;
2095         if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
2096         if (errno == ENOSPC)
2097             SetLastError( ERROR_DISK_FULL );
2098         else
2099         FILE_SetDosError();
2100         break;
2101     }
2102     close( unix_handle );
2103     if (result == -1) return FALSE;
2104     if (bytesWritten) *bytesWritten = result;
2105     return TRUE;
2106 }
2107
2108
2109 /***********************************************************************
2110  *           SetFilePointer   (KERNEL32.@)
2111  */
2112 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2113                              DWORD method )
2114 {
2115     DWORD ret = INVALID_SET_FILE_POINTER;
2116
2117     TRACE("handle %p offset %ld high %ld origin %ld\n",
2118           hFile, distance, highword?*highword:0, method );
2119
2120     SERVER_START_REQ( set_file_pointer )
2121     {
2122         req->handle = hFile;
2123         req->low = distance;
2124         req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2125         /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2126         req->whence = method;
2127         SetLastError( 0 );
2128         if (!wine_server_call_err( req ))
2129         {
2130             ret = reply->new_low;
2131             if (highword) *highword = reply->new_high;
2132         }
2133     }
2134     SERVER_END_REQ;
2135     return ret;
2136 }
2137
2138
2139 /*************************************************************************
2140  *           SetHandleCount   (KERNEL32.@)
2141  */
2142 UINT WINAPI SetHandleCount( UINT count )
2143 {
2144     return min( 256, count );
2145 }
2146
2147
2148 /**************************************************************************
2149  *           SetEndOfFile   (KERNEL32.@)
2150  */
2151 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2152 {
2153     BOOL ret;
2154     SERVER_START_REQ( truncate_file )
2155     {
2156         req->handle = hFile;
2157         ret = !wine_server_call_err( req );
2158     }
2159     SERVER_END_REQ;
2160     return ret;
2161 }
2162
2163
2164 /***********************************************************************
2165  *           DeleteFileW   (KERNEL32.@)
2166  */
2167 BOOL WINAPI DeleteFileW( LPCWSTR path )
2168 {
2169     DOS_FULL_NAME full_name;
2170     HANDLE hFile;
2171
2172     TRACE("%s\n", debugstr_w(path) );
2173     if (!path || !*path)
2174     {
2175         SetLastError(ERROR_PATH_NOT_FOUND);
2176         return FALSE;
2177     }
2178     if (DOSFS_GetDevice( path ))
2179     {
2180         WARN("cannot remove DOS device %s!\n", debugstr_w(path));
2181         SetLastError( ERROR_FILE_NOT_FOUND );
2182         return FALSE;
2183     }
2184
2185     if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2186
2187     /* check if we are allowed to delete the source */
2188     hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2189                              NULL, OPEN_EXISTING, 0, 0, TRUE,
2190                              GetDriveTypeW( full_name.short_name ) );
2191     if (!hFile) return FALSE;
2192
2193     if (unlink( full_name.long_name ) == -1)
2194     {
2195         FILE_SetDosError();
2196         CloseHandle(hFile);
2197         return FALSE;
2198     }
2199     CloseHandle(hFile);
2200     return TRUE;
2201 }
2202
2203
2204 /***********************************************************************
2205  *           DeleteFileA   (KERNEL32.@)
2206  */
2207 BOOL WINAPI DeleteFileA( LPCSTR path )
2208 {
2209     UNICODE_STRING pathW;
2210     BOOL ret = FALSE;
2211
2212     if (!path)
2213     {
2214         SetLastError(ERROR_INVALID_PARAMETER);
2215         return FALSE;
2216     }
2217
2218     if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
2219     {
2220         ret = DeleteFileW(pathW.Buffer);
2221         RtlFreeUnicodeString(&pathW);
2222     }
2223     else
2224         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2225     return ret;
2226 }
2227
2228
2229 /***********************************************************************
2230  *           GetFileType   (KERNEL32.@)
2231  */
2232 DWORD WINAPI GetFileType( HANDLE hFile )
2233 {
2234     DWORD ret = FILE_TYPE_UNKNOWN;
2235
2236     if (is_console_handle( hFile ))
2237         return FILE_TYPE_CHAR;
2238
2239     SERVER_START_REQ( get_file_info )
2240     {
2241         req->handle = hFile;
2242         if (!wine_server_call_err( req )) ret = reply->type;
2243     }
2244     SERVER_END_REQ;
2245     return ret;
2246 }
2247
2248
2249 /* check if a file name is for an executable file (.exe or .com) */
2250 inline static BOOL is_executable( const char *name )
2251 {
2252     int len = strlen(name);
2253
2254     if (len < 4) return FALSE;
2255     return (!strcasecmp( name + len - 4, ".exe" ) ||
2256             !strcasecmp( name + len - 4, ".com" ));
2257 }
2258
2259
2260 /***********************************************************************
2261  *           FILE_AddBootRenameEntry
2262  *
2263  * Adds an entry to the registry that is loaded when windows boots and
2264  * checks if there are some files to be removed or renamed/moved.
2265  * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2266  * non-NULL then the file is moved, otherwise it is deleted.  The
2267  * entry of the registrykey is always appended with two zero
2268  * terminated strings. If <fn2> is NULL then the second entry is
2269  * simply a single 0-byte. Otherwise the second filename goes
2270  * there. The entries are prepended with \??\ before the path and the
2271  * second filename gets also a '!' as the first character if
2272  * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2273  * 0-byte follows to indicate the end of the strings.
2274  * i.e.:
2275  * \??\D:\test\file1[0]
2276  * !\??\D:\test\file1_renamed[0]
2277  * \??\D:\Test|delete[0]
2278  * [0]                        <- file is to be deleted, second string empty
2279  * \??\D:\test\file2[0]
2280  * !\??\D:\test\file2_renamed[0]
2281  * [0]                        <- indicates end of strings
2282  *
2283  * or:
2284  * \??\D:\test\file1[0]
2285  * !\??\D:\test\file1_renamed[0]
2286  * \??\D:\Test|delete[0]
2287  * [0]                        <- file is to be deleted, second string empty
2288  * [0]                        <- indicates end of strings
2289  *
2290  */
2291 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
2292 {
2293     static const WCHAR PreString[] = {'\\','?','?','\\',0};
2294     static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
2295                                       'F','i','l','e','R','e','n','a','m','e',
2296                                       'O','p','e','r','a','t','i','o','n','s',0};
2297     static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
2298                                      'S','y','s','t','e','m','\\',
2299                                      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
2300                                      'C','o','n','t','r','o','l','\\',
2301                                      'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
2302     static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
2303
2304     OBJECT_ATTRIBUTES attr;
2305     UNICODE_STRING nameW;
2306     KEY_VALUE_PARTIAL_INFORMATION *info;
2307     BOOL rc = FALSE;
2308     HKEY Reboot = 0;
2309     DWORD len0, len1, len2;
2310     DWORD DataSize = 0;
2311     BYTE *Buffer = NULL;
2312     WCHAR *p;
2313
2314     attr.Length = sizeof(attr);
2315     attr.RootDirectory = 0;
2316     attr.ObjectName = &nameW;
2317     attr.Attributes = 0;
2318     attr.SecurityDescriptor = NULL;
2319     attr.SecurityQualityOfService = NULL;
2320     RtlInitUnicodeString( &nameW, SessionW );
2321
2322     if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
2323     {
2324         WARN("Error creating key for reboot managment [%s]\n",
2325              "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2326         return FALSE;
2327     }
2328
2329     len0 = strlenW(PreString);
2330     len1 = strlenW(fn1) + len0 + 1;
2331     if (fn2)
2332     {
2333         len2 = strlenW(fn2) + len0 + 1;
2334         if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2335     }
2336     else len2 = 1; /* minimum is the 0 characters for the empty second string */
2337
2338     /* convert characters to bytes */
2339     len0 *= sizeof(WCHAR);
2340     len1 *= sizeof(WCHAR);
2341     len2 *= sizeof(WCHAR);
2342
2343     RtlInitUnicodeString( &nameW, ValueName );
2344
2345     /* First we check if the key exists and if so how many bytes it already contains. */
2346     if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2347                          NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
2348     {
2349         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2350             goto Quit;
2351         if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
2352                              Buffer, DataSize, &DataSize )) goto Quit;
2353         info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
2354         if (info->Type != REG_MULTI_SZ) goto Quit;
2355         if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR);  /* remove terminating null (will be added back later) */
2356     }
2357     else
2358     {
2359         DataSize = info_size;
2360         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
2361             goto Quit;
2362     }
2363
2364     p = (WCHAR *)(Buffer + DataSize);
2365     strcpyW( p, PreString );
2366     strcatW( p, fn1 );
2367     DataSize += len1;
2368     if (fn2)
2369     {
2370         p = (WCHAR *)(Buffer + DataSize);
2371         if (flags & MOVEFILE_REPLACE_EXISTING)
2372             *p++ = '!';
2373         strcpyW( p, PreString );
2374         strcatW( p, fn2 );
2375         DataSize += len2;
2376     }
2377     else
2378     {
2379         p = (WCHAR *)(Buffer + DataSize);
2380         *p = 0;
2381         DataSize += sizeof(WCHAR);
2382     }
2383
2384     /* add final null */
2385     p = (WCHAR *)(Buffer + DataSize);
2386     *p = 0;
2387     DataSize += sizeof(WCHAR);
2388
2389     rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
2390
2391  Quit:
2392     if (Reboot) NtClose(Reboot);
2393     if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2394     return(rc);
2395 }
2396
2397
2398 /**************************************************************************
2399  *           MoveFileExW   (KERNEL32.@)
2400  */
2401 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2402 {
2403     DOS_FULL_NAME full_name1, full_name2;
2404     HANDLE hFile;
2405     DWORD attr = INVALID_FILE_ATTRIBUTES;
2406
2407     TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
2408
2409     /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2410        In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2411        to be really compatible. Most programs wont have any problems though. In case
2412        you encounter one, this is what you should return here. I don't know what's up
2413        with NT 3.5. Is this function available there or not?
2414        Does anybody really care about 3.5? :)
2415     */
2416
2417     /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2418        if the source file has to be deleted.
2419     */
2420     if (!fn1) {
2421         SetLastError(ERROR_INVALID_PARAMETER);
2422         return FALSE;
2423     }
2424
2425     /* This function has to be run through in order to process the name properly.
2426        If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2427        that is the behaviour on NT 4.0. The operation accepts the filenames as
2428        they are given but it can't reply with a reasonable returncode. Success
2429        means in that case success for entering the values into the registry.
2430     */
2431     if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2432     {
2433         if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2434             return FALSE;
2435     }
2436
2437     if (fn2)  /* !fn2 means delete fn1 */
2438     {
2439         if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2440         {
2441             if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2442             {
2443                 /* target exists, check if we may overwrite */
2444                 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2445                 {
2446                     SetLastError( ERROR_FILE_EXISTS );
2447                     return FALSE;
2448                 }
2449             }
2450         }
2451         else
2452         {
2453             if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2454             {
2455                 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2456                     return FALSE;
2457             }
2458         }
2459
2460         /* Source name and target path are valid */
2461
2462         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2463         {
2464             return FILE_AddBootRenameEntry( fn1, fn2, flag );
2465         }
2466
2467         attr = GetFileAttributesW( fn1 );
2468         if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
2469
2470         /* check if we are allowed to rename the source */
2471         hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
2472                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2473                                  GetDriveTypeW( full_name1.short_name ) );
2474         if (!hFile)
2475         {
2476             if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
2477             if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
2478             /* if it's a directory we can continue */
2479         }
2480         else CloseHandle(hFile);
2481
2482         /* check, if we are allowed to delete the destination,
2483         **     (but the file not being there is fine) */
2484         hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2485                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2486                                  GetDriveTypeW( full_name2.short_name ) );
2487         if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2488         CloseHandle(hFile);
2489
2490         if (full_name1.drive != full_name2.drive)
2491         {
2492             if (!(flag & MOVEFILE_COPY_ALLOWED))
2493             {
2494                 SetLastError( ERROR_NOT_SAME_DEVICE );
2495                 return FALSE;
2496             }
2497             else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2498             {
2499                 /* Strange, but that's what Windows returns */
2500                 SetLastError ( ERROR_ACCESS_DENIED );
2501                 return FALSE;
2502             }
2503         }
2504         if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2505             /* Try copy/delete unless it's a directory. */
2506             /* FIXME: This does not handle the (unlikely) case that the two locations
2507                are on the same Wine drive, but on different Unix file systems. */
2508         {
2509             if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2510             {
2511                 FILE_SetDosError();
2512                 return FALSE;
2513             }
2514             else
2515             {
2516                 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2517                     return FALSE;
2518                 if ( ! DeleteFileW ( fn1 ) )
2519                     return FALSE;
2520             }
2521         }
2522         if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2523         {
2524             struct stat fstat;
2525             if (stat( full_name2.long_name, &fstat ) != -1)
2526             {
2527                 if (is_executable( full_name2.long_name ))
2528                     /* set executable bit where read bit is set */
2529                     fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2530                 else
2531                     fstat.st_mode &= ~0111;
2532                 chmod( full_name2.long_name, fstat.st_mode );
2533             }
2534         }
2535         return TRUE;
2536     }
2537     else /* fn2 == NULL means delete source */
2538     {
2539         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2540         {
2541             if (flag & MOVEFILE_COPY_ALLOWED) {
2542                 WARN("Illegal flag\n");
2543                 SetLastError( ERROR_GEN_FAILURE );
2544                 return FALSE;
2545             }
2546
2547             return FILE_AddBootRenameEntry( fn1, NULL, flag );
2548         }
2549
2550         if (unlink( full_name1.long_name ) == -1)
2551         {
2552             FILE_SetDosError();
2553             return FALSE;
2554         }
2555         return TRUE; /* successfully deleted */
2556     }
2557 }
2558
2559 /**************************************************************************
2560  *           MoveFileExA   (KERNEL32.@)
2561  */
2562 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2563 {
2564     UNICODE_STRING fn1W, fn2W;
2565     BOOL ret;
2566
2567     if (!fn1)
2568     {
2569         SetLastError(ERROR_INVALID_PARAMETER);
2570         return FALSE;
2571     }
2572
2573     RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2574     if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2575     else fn2W.Buffer = NULL;
2576
2577     ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2578
2579     RtlFreeUnicodeString(&fn1W);
2580     RtlFreeUnicodeString(&fn2W);
2581     return ret;
2582 }
2583
2584
2585 /**************************************************************************
2586  *           MoveFileW   (KERNEL32.@)
2587  *
2588  *  Move file or directory
2589  */
2590 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2591 {
2592     return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2593 }
2594
2595
2596 /**************************************************************************
2597  *           MoveFileA   (KERNEL32.@)
2598  */
2599 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2600 {
2601     return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2602 }
2603
2604
2605 /**************************************************************************
2606  *           CopyFileW   (KERNEL32.@)
2607  */
2608 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2609 {
2610     HANDLE h1, h2;
2611     BY_HANDLE_FILE_INFORMATION info;
2612     DWORD count;
2613     BOOL ret = FALSE;
2614     char buffer[2048];
2615
2616     if (!source || !dest)
2617     {
2618         SetLastError(ERROR_INVALID_PARAMETER);
2619         return FALSE;
2620     }
2621
2622     TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2623
2624     if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2625                      NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2626     {
2627         WARN("Unable to open source %s\n", debugstr_w(source));
2628         return FALSE;
2629     }
2630
2631     if (!GetFileInformationByHandle( h1, &info ))
2632     {
2633         WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2634         CloseHandle( h1 );
2635         return FALSE;
2636     }
2637
2638     if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2639                              fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2640                              info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2641     {
2642         WARN("Unable to open dest %s\n", debugstr_w(dest));
2643         CloseHandle( h1 );
2644         return FALSE;
2645     }
2646
2647     while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2648     {
2649         char *p = buffer;
2650         while (count != 0)
2651         {
2652             DWORD res;
2653             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2654             p += res;
2655             count -= res;
2656         }
2657     }
2658     ret =  TRUE;
2659 done:
2660     CloseHandle( h1 );
2661     CloseHandle( h2 );
2662     return ret;
2663 }
2664
2665
2666 /**************************************************************************
2667  *           CopyFileA   (KERNEL32.@)
2668  */
2669 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2670 {
2671     UNICODE_STRING sourceW, destW;
2672     BOOL ret;
2673
2674     if (!source || !dest)
2675     {
2676         SetLastError(ERROR_INVALID_PARAMETER);
2677         return FALSE;
2678     }
2679
2680     RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2681     RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2682
2683     ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2684
2685     RtlFreeUnicodeString(&sourceW);
2686     RtlFreeUnicodeString(&destW);
2687     return ret;
2688 }
2689
2690
2691 /**************************************************************************
2692  *           CopyFileExW   (KERNEL32.@)
2693  *
2694  * This implementation ignores most of the extra parameters passed-in into
2695  * the "ex" version of the method and calls the CopyFile method.
2696  * It will have to be fixed eventually.
2697  */
2698 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2699                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2700                         LPBOOL cancelFlagPointer, DWORD copyFlags)
2701 {
2702     /*
2703      * Interpret the only flag that CopyFile can interpret.
2704      */
2705     return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2706 }
2707
2708
2709 /**************************************************************************
2710  *           CopyFileExA   (KERNEL32.@)
2711  */
2712 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2713                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2714                         LPBOOL cancelFlagPointer, DWORD copyFlags)
2715 {
2716     UNICODE_STRING sourceW, destW;
2717     BOOL ret;
2718
2719     if (!sourceFilename || !destFilename)
2720     {
2721         SetLastError(ERROR_INVALID_PARAMETER);
2722         return FALSE;
2723     }
2724
2725     RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2726     RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2727
2728     ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2729                       cancelFlagPointer, copyFlags);
2730
2731     RtlFreeUnicodeString(&sourceW);
2732     RtlFreeUnicodeString(&destW);
2733     return ret;
2734 }
2735
2736
2737 /***********************************************************************
2738  *              SetFileTime   (KERNEL32.@)
2739  */
2740 BOOL WINAPI SetFileTime( HANDLE hFile,
2741                            const FILETIME *lpCreationTime,
2742                            const FILETIME *lpLastAccessTime,
2743                            const FILETIME *lpLastWriteTime )
2744 {
2745     BOOL ret;
2746     SERVER_START_REQ( set_file_time )
2747     {
2748         req->handle = hFile;
2749         if (lpLastAccessTime)
2750             RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2751         else
2752             req->access_time = 0; /* FIXME */
2753         if (lpLastWriteTime)
2754             RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2755         else
2756             req->write_time = 0; /* FIXME */
2757         ret = !wine_server_call_err( req );
2758     }
2759     SERVER_END_REQ;
2760     return ret;
2761 }
2762
2763
2764 /**************************************************************************
2765  *           GetFileAttributesExW   (KERNEL32.@)
2766  */
2767 BOOL WINAPI GetFileAttributesExW(
2768         LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2769         LPVOID lpFileInformation)
2770 {
2771     DOS_FULL_NAME full_name;
2772     BY_HANDLE_FILE_INFORMATION info;
2773
2774     if (!lpFileName || !lpFileInformation)
2775     {
2776         SetLastError(ERROR_INVALID_PARAMETER);
2777         return FALSE;
2778     }
2779
2780     if (fInfoLevelId == GetFileExInfoStandard) {
2781         LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2782             (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2783         if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2784         if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2785
2786         lpFad->dwFileAttributes = info.dwFileAttributes;
2787         lpFad->ftCreationTime   = info.ftCreationTime;
2788         lpFad->ftLastAccessTime = info.ftLastAccessTime;
2789         lpFad->ftLastWriteTime  = info.ftLastWriteTime;
2790         lpFad->nFileSizeHigh    = info.nFileSizeHigh;
2791         lpFad->nFileSizeLow     = info.nFileSizeLow;
2792     }
2793     else {
2794         FIXME("invalid info level %d!\n", fInfoLevelId);
2795         return FALSE;
2796     }
2797
2798     return TRUE;
2799 }
2800
2801
2802 /**************************************************************************
2803  *           GetFileAttributesExA   (KERNEL32.@)
2804  */
2805 BOOL WINAPI GetFileAttributesExA(
2806         LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2807         LPVOID lpFileInformation)
2808 {
2809     UNICODE_STRING filenameW;
2810     BOOL ret = FALSE;
2811
2812     if (!filename || !lpFileInformation)
2813     {
2814         SetLastError(ERROR_INVALID_PARAMETER);
2815         return FALSE;
2816     }
2817
2818     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2819     {
2820         ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2821         RtlFreeUnicodeString(&filenameW);
2822     }
2823     else
2824         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2825     return ret;
2826 }