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