Fix subclassing to support nested messages.
[wine] / files / file.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 John Burton
5  * Copyright 1996 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * TODO:
22  *    Fix the CopyFileEx methods to implement the "extended" functionality.
23  *    Right now, they simply call the CopyFile method.
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_SYS_ERRNO_H
38 #include <sys/errno.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 #endif
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
50 #endif
51 #include <time.h>
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
55 #ifdef HAVE_UTIME_H
56 # include <utime.h>
57 #endif
58
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61 #include "winerror.h"
62 #include "ntstatus.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "winreg.h"
66 #include "winternl.h"
67 #include "wine/winbase16.h"
68 #include "wine/server.h"
69
70 #include "file.h"
71 #include "wincon.h"
72 #include "kernel_private.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 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
85
86 mode_t FILE_umask;
87
88 /***********************************************************************
89  *              FILE_ConvertOFMode
90  *
91  * Convert OF_* mode into flags for CreateFile.
92  */
93 void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
94 {
95     switch(mode & 0x03)
96     {
97     case OF_READ:      *access = GENERIC_READ; break;
98     case OF_WRITE:     *access = GENERIC_WRITE; break;
99     case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
100     default:           *access = 0; break;
101     }
102     switch(mode & 0x70)
103     {
104     case OF_SHARE_EXCLUSIVE:  *sharing = 0; break;
105     case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
106     case OF_SHARE_DENY_READ:  *sharing = FILE_SHARE_WRITE; break;
107     case OF_SHARE_DENY_NONE:
108     case OF_SHARE_COMPAT:
109     default:                  *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
110     }
111 }
112
113
114 /***********************************************************************
115  *           FILE_SetDosError
116  *
117  * Set the DOS error code from errno.
118  */
119 void FILE_SetDosError(void)
120 {
121     int save_errno = errno; /* errno gets overwritten by printf */
122
123     TRACE("errno = %d %s\n", errno, strerror(errno));
124     switch (save_errno)
125     {
126     case EAGAIN:
127         SetLastError( ERROR_SHARING_VIOLATION );
128         break;
129     case EBADF:
130         SetLastError( ERROR_INVALID_HANDLE );
131         break;
132     case ENOSPC:
133         SetLastError( ERROR_HANDLE_DISK_FULL );
134         break;
135     case EACCES:
136     case EPERM:
137     case EROFS:
138         SetLastError( ERROR_ACCESS_DENIED );
139         break;
140     case EBUSY:
141         SetLastError( ERROR_LOCK_VIOLATION );
142         break;
143     case ENOENT:
144         SetLastError( ERROR_FILE_NOT_FOUND );
145         break;
146     case EISDIR:
147         SetLastError( ERROR_CANNOT_MAKE );
148         break;
149     case ENFILE:
150     case EMFILE:
151         SetLastError( ERROR_NO_MORE_FILES );
152         break;
153     case EEXIST:
154         SetLastError( ERROR_FILE_EXISTS );
155         break;
156     case EINVAL:
157     case ESPIPE:
158         SetLastError( ERROR_SEEK );
159         break;
160     case ENOTEMPTY:
161         SetLastError( ERROR_DIR_NOT_EMPTY );
162         break;
163     case ENOEXEC:
164         SetLastError( ERROR_BAD_FORMAT );
165         break;
166     default:
167         WARN("unknown file error: %s\n", strerror(save_errno) );
168         SetLastError( ERROR_GEN_FAILURE );
169         break;
170     }
171     errno = save_errno;
172 }
173
174
175 /***********************************************************************
176  *           FILE_CreateFile
177  *
178  * Implementation of CreateFile. Takes a Unix path name.
179  * Returns 0 on failure.
180  */
181 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
182                         LPSECURITY_ATTRIBUTES sa, DWORD creation,
183                         DWORD attributes, HANDLE template, BOOL fail_read_only,
184                         UINT drive_type )
185 {
186     unsigned int err;
187     HANDLE ret;
188
189     for (;;)
190     {
191         SERVER_START_REQ( create_file )
192         {
193             req->access     = access;
194             req->inherit    = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
195             req->sharing    = sharing;
196             req->create     = creation;
197             req->attrs      = attributes;
198             req->removable  = (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM);
199             wine_server_add_data( req, filename, strlen(filename) );
200             SetLastError(0);
201             err = wine_server_call( req );
202             ret = reply->handle;
203         }
204         SERVER_END_REQ;
205
206         /* If write access failed, retry without GENERIC_WRITE */
207
208         if (!ret && !fail_read_only && (access & GENERIC_WRITE))
209         {
210             if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
211             {
212                 TRACE("Write access failed for file '%s', trying without "
213                       "write access\n", filename);
214                 access &= ~GENERIC_WRITE;
215                 continue;
216             }
217         }
218
219         if (err)
220         {
221             /* In the case file creation was rejected due to CREATE_NEW flag
222              * was specified and file with that name already exists, correct
223              * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
224              * Note: RtlNtStatusToDosError is not the subject to blame here.
225              */
226             if (err == STATUS_OBJECT_NAME_COLLISION)
227                 SetLastError( ERROR_FILE_EXISTS );
228             else
229                 SetLastError( RtlNtStatusToDosError(err) );
230         }
231
232         if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
233         return ret;
234     }
235 }
236
237
238 static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa )
239 {
240     HANDLE ret;
241     DWORD len = 0;
242
243     if (name && (len = strlenW(name)) > MAX_PATH)
244     {
245         SetLastError( ERROR_FILENAME_EXCED_RANGE );
246         return 0;
247     }
248     SERVER_START_REQ( open_named_pipe )
249     {
250         req->access = access;
251         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
252         SetLastError(0);
253         wine_server_add_data( req, name, len * sizeof(WCHAR) );
254         wine_server_call_err( req );
255         ret = reply->handle;
256     }
257     SERVER_END_REQ;
258     TRACE("Returned %p\n",ret);
259     return ret;
260 }
261
262 /*************************************************************************
263  * CreateFileW [KERNEL32.@]  Creates or opens a file or other object
264  *
265  * Creates or opens an object, and returns a handle that can be used to
266  * access that object.
267  *
268  * PARAMS
269  *
270  * filename     [in] pointer to filename to be accessed
271  * access       [in] access mode requested
272  * sharing      [in] share mode
273  * sa           [in] pointer to security attributes
274  * creation     [in] how to create the file
275  * attributes   [in] attributes for newly created file
276  * template     [in] handle to file with extended attributes to copy
277  *
278  * RETURNS
279  *   Success: Open handle to specified file
280  *   Failure: INVALID_HANDLE_VALUE
281  *
282  * NOTES
283  *  Should call SetLastError() on failure.
284  *
285  * BUGS
286  *
287  * Doesn't support character devices, template files, or a
288  * lot of the 'attributes' flags yet.
289  */
290 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
291                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
292                               DWORD attributes, HANDLE template )
293 {
294     DOS_FULL_NAME full_name;
295     HANDLE ret;
296     static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0};
297     static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
298     static const WCHAR bkslashesW[] = {'\\','\\',0};
299     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
300     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
301
302     if (!filename)
303     {
304         SetLastError( ERROR_INVALID_PARAMETER );
305         return INVALID_HANDLE_VALUE;
306     }
307     TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename),
308           ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
309           ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
310           (!access)?"QUERY_ACCESS ":"",
311           ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
312           ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
313           ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
314           (creation ==CREATE_NEW)?"CREATE_NEW":
315           (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
316           (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
317           (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
318           (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes);
319
320     /* If the name starts with '\\?\', ignore the first 4 chars. */
321     if (!strncmpW(filename, bkslashes_with_question_markW, 4))
322     {
323         static const WCHAR uncW[] = {'U','N','C','\\',0};
324         filename += 4;
325         if (!strncmpiW(filename, uncW, 4))
326         {
327             FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) );
328             SetLastError( ERROR_PATH_NOT_FOUND );
329             return INVALID_HANDLE_VALUE;
330         }
331     }
332
333     if (!strncmpW(filename, bkslashes_with_dotW, 4))
334     {
335         static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
336         if(!strncmpiW(filename + 4, pipeW, 5))
337         {
338             TRACE("Opening a pipe: %s\n", debugstr_w(filename));
339             ret = FILE_OpenPipe( filename, access, sa );
340             goto done;
341         }
342         else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0')
343         {
344             const char *device = DRIVE_GetDevice( toupperW(filename[4]) - 'A' );
345             if (device)
346             {
347                 ret = FILE_CreateFile( device, access, sharing, sa, creation,
348                                        attributes, template, TRUE, DRIVE_FIXED );
349             }
350             else
351             {
352                 SetLastError( ERROR_ACCESS_DENIED );
353                 ret = INVALID_HANDLE_VALUE;
354             }
355             goto done;
356         }
357         else if (!RtlIsDosDeviceName_U( filename ))
358         {
359             ret = VXD_Open( filename+4, access, sa );
360             goto done;
361         }
362         else
363                 filename+=4; /* fall into DOSFS_Device case below */
364     }
365
366     /* If the name still starts with '\\', it's a UNC name. */
367     if (!strncmpW(filename, bkslashesW, 2))
368     {
369         ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template );
370         goto done;
371     }
372
373     /* If the name contains a DOS wild card (* or ?), do no create a file */
374     if(strchrW(filename, '*') || strchrW(filename, '?'))
375     {
376         SetLastError(ERROR_BAD_PATHNAME);
377         return INVALID_HANDLE_VALUE;
378     }
379
380     /* Open a console for CONIN$ or CONOUT$ */
381     if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
382     {
383         ret = OpenConsoleW(filename, access, sa, creation);
384         goto done;
385     }
386
387     if (RtlIsDosDeviceName_U( filename ))
388     {
389         TRACE("opening device %s\n", debugstr_w(filename) );
390
391         if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa )))
392         {
393             /* Do not silence this please. It is a critical error. -MM */
394             ERR("Couldn't open device %s!\n", debugstr_w(filename));
395             SetLastError( ERROR_FILE_NOT_FOUND );
396         }
397         goto done;
398     }
399
400     /* check for filename, don't check for last entry if creating */
401     if (!DOSFS_GetFullName( filename,
402                             (creation == OPEN_EXISTING) ||
403                             (creation == TRUNCATE_EXISTING),
404                             &full_name )) {
405         WARN("Unable to get full filename from %s (GLE %ld)\n",
406              debugstr_w(filename), GetLastError());
407         return INVALID_HANDLE_VALUE;
408     }
409
410     ret = FILE_CreateFile( full_name.long_name, access, sharing,
411                            sa, creation, attributes, template,
412                            DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
413                            GetDriveTypeW( full_name.short_name ) );
414  done:
415     if (!ret) ret = INVALID_HANDLE_VALUE;
416     TRACE("returning %p\n", ret);
417     return ret;
418 }
419
420
421
422 /*************************************************************************
423  *              CreateFileA              (KERNEL32.@)
424  */
425 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
426                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
427                               DWORD attributes, HANDLE template)
428 {
429     UNICODE_STRING filenameW;
430     HANDLE ret = INVALID_HANDLE_VALUE;
431
432     if (!filename)
433     {
434         SetLastError( ERROR_INVALID_PARAMETER );
435         return INVALID_HANDLE_VALUE;
436     }
437
438     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
439     {
440         ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation,
441                           attributes, template);
442         RtlFreeUnicodeString(&filenameW);
443     }
444     else
445         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
446     return ret;
447 }
448
449
450 /***********************************************************************
451  *           FILE_FillInfo
452  *
453  * Fill a file information from a struct stat.
454  */
455 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
456 {
457     if (S_ISDIR(st->st_mode))
458         info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
459     else
460         info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
461     if (!(st->st_mode & S_IWUSR))
462         info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
463
464     RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftCreationTime );
465     RtlSecondsSince1970ToTime( st->st_mtime, (LARGE_INTEGER *)&info->ftLastWriteTime );
466     RtlSecondsSince1970ToTime( st->st_atime, (LARGE_INTEGER *)&info->ftLastAccessTime );
467
468     info->dwVolumeSerialNumber = 0;  /* FIXME */
469     info->nFileSizeHigh = 0;
470     info->nFileSizeLow  = 0;
471     if (!S_ISDIR(st->st_mode)) {
472         info->nFileSizeHigh = st->st_size >> 32;
473         info->nFileSizeLow  = st->st_size & 0xffffffff;
474     }
475     info->nNumberOfLinks = st->st_nlink;
476     info->nFileIndexHigh = 0;
477     info->nFileIndexLow  = st->st_ino;
478 }
479
480
481 /***********************************************************************
482  *           get_show_dot_files_option
483  */
484 static BOOL get_show_dot_files_option(void)
485 {
486     static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
487                                   'S','o','f','t','w','a','r','e','\\',
488                                   'W','i','n','e','\\','W','i','n','e','\\',
489                                   'C','o','n','f','i','g','\\','W','i','n','e',0};
490     static const WCHAR ShowDotFilesW[] = {'S','h','o','w','D','o','t','F','i','l','e','s',0};
491
492     char tmp[80];
493     HKEY hkey;
494     DWORD dummy;
495     OBJECT_ATTRIBUTES attr;
496     UNICODE_STRING nameW;
497     BOOL ret = FALSE;
498
499     attr.Length = sizeof(attr);
500     attr.RootDirectory = 0;
501     attr.ObjectName = &nameW;
502     attr.Attributes = 0;
503     attr.SecurityDescriptor = NULL;
504     attr.SecurityQualityOfService = NULL;
505     RtlInitUnicodeString( &nameW, WineW );
506
507     if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
508     {
509         RtlInitUnicodeString( &nameW, ShowDotFilesW );
510         if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
511         {
512             WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
513             ret = IS_OPTION_TRUE( str[0] );
514         }
515         NtClose( hkey );
516     }
517     return ret;
518 }
519
520
521 /***********************************************************************
522  *           FILE_Stat
523  *
524  * Stat a Unix path name. Return TRUE if OK.
525  */
526 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info, BOOL *is_symlink_ptr )
527 {
528     struct stat st;
529     int is_symlink;
530     LPCSTR p;
531
532     if (lstat( unixName, &st ) == -1)
533     {
534         FILE_SetDosError();
535         return FALSE;
536     }
537     is_symlink = S_ISLNK(st.st_mode);
538     if (is_symlink)
539     {
540         /* do a "real" stat to find out
541            about the type of the symlink destination */
542         if (stat( unixName, &st ) == -1)
543         {
544             FILE_SetDosError();
545             return FALSE;
546         }
547     }
548
549     /* fill in the information we gathered so far */
550     FILE_FillInfo( &st, info );
551
552     /* and now see if this is a hidden file, based on the name */
553     p = strrchr( unixName, '/');
554     p = p ? p + 1 : unixName;
555     if (*p == '.' && *(p+1)  && (*(p+1) != '.' || *(p+2)))
556     {
557         static int show_dot_files = -1;
558         if (show_dot_files == -1)
559             show_dot_files = get_show_dot_files_option();
560         if (!show_dot_files)
561             info->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
562     }
563     if (is_symlink_ptr) *is_symlink_ptr = is_symlink;
564     return TRUE;
565 }
566
567
568 /***********************************************************************
569  *             GetFileInformationByHandle   (KERNEL32.@)
570  */
571 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
572                                          BY_HANDLE_FILE_INFORMATION *info )
573 {
574     DWORD ret;
575     if (!info) return 0;
576
577     TRACE("%p\n", hFile);
578
579     SERVER_START_REQ( get_file_info )
580     {
581         req->handle = hFile;
582         if ((ret = !wine_server_call_err( req )))
583         {
584             /* FIXME: which file types are supported ?
585              * Serial ports (FILE_TYPE_CHAR) are not,
586              * and MSDN also says that pipes are not supported.
587              * FILE_TYPE_REMOTE seems to be supported according to
588              * MSDN q234741.txt */
589             if ((reply->type == FILE_TYPE_DISK) ||  (reply->type == FILE_TYPE_REMOTE))
590             {
591                 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftCreationTime );
592                 RtlSecondsSince1970ToTime( reply->write_time, (LARGE_INTEGER *)&info->ftLastWriteTime );
593                 RtlSecondsSince1970ToTime( reply->access_time, (LARGE_INTEGER *)&info->ftLastAccessTime );
594                 info->dwFileAttributes     = reply->attr;
595                 info->dwVolumeSerialNumber = reply->serial;
596                 info->nFileSizeHigh        = reply->size_high;
597                 info->nFileSizeLow         = reply->size_low;
598                 info->nNumberOfLinks       = reply->links;
599                 info->nFileIndexHigh       = reply->index_high;
600                 info->nFileIndexLow        = reply->index_low;
601             }
602             else
603             {
604                 SetLastError(ERROR_NOT_SUPPORTED);
605                 ret = 0;
606             }
607         }
608     }
609     SERVER_END_REQ;
610     return ret;
611 }
612
613
614 /**************************************************************************
615  *           GetFileAttributesW   (KERNEL32.@)
616  */
617 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
618 {
619     DOS_FULL_NAME full_name;
620     BY_HANDLE_FILE_INFORMATION info;
621
622     if (name == NULL)
623     {
624         SetLastError( ERROR_INVALID_PARAMETER );
625         return INVALID_FILE_ATTRIBUTES;
626     }
627     if (!DOSFS_GetFullName( name, TRUE, &full_name) )
628         return INVALID_FILE_ATTRIBUTES;
629     if (!FILE_Stat( full_name.long_name, &info, NULL ))
630         return INVALID_FILE_ATTRIBUTES;
631     return info.dwFileAttributes;
632 }
633
634
635 /**************************************************************************
636  *           GetFileAttributesA   (KERNEL32.@)
637  */
638 DWORD WINAPI GetFileAttributesA( LPCSTR name )
639 {
640     UNICODE_STRING nameW;
641     DWORD ret = INVALID_FILE_ATTRIBUTES;
642
643     if (!name)
644     {
645         SetLastError( ERROR_INVALID_PARAMETER );
646         return INVALID_FILE_ATTRIBUTES;
647     }
648
649     if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
650     {
651         ret = GetFileAttributesW(nameW.Buffer);
652         RtlFreeUnicodeString(&nameW);
653     }
654     else
655         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
656     return ret;
657 }
658
659
660 /**************************************************************************
661  *              SetFileAttributesW      (KERNEL32.@)
662  */
663 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
664 {
665     struct stat buf;
666     DOS_FULL_NAME full_name;
667
668     if (!lpFileName)
669     {
670         SetLastError( ERROR_INVALID_PARAMETER );
671         return FALSE;
672     }
673
674     TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes);
675
676     if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
677         return FALSE;
678
679     if(stat(full_name.long_name,&buf)==-1)
680     {
681         FILE_SetDosError();
682         return FALSE;
683     }
684     if (attributes & FILE_ATTRIBUTE_READONLY)
685     {
686         if(S_ISDIR(buf.st_mode))
687             /* FIXME */
688             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
689         else
690             buf.st_mode &= ~0222; /* octal!, clear write permission bits */
691         attributes &= ~FILE_ATTRIBUTE_READONLY;
692     }
693     else
694     {
695         /* add write permission */
696         buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
697     }
698     if (attributes & FILE_ATTRIBUTE_DIRECTORY)
699     {
700         if (!S_ISDIR(buf.st_mode))
701             FIXME("SetFileAttributes expected the file %s to be a directory\n",
702                   debugstr_w(lpFileName));
703         attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
704     }
705     attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|
706                     FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY);
707     if (attributes)
708         FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes);
709     if (-1==chmod(full_name.long_name,buf.st_mode))
710     {
711         if (GetDriveTypeW(lpFileName) == DRIVE_CDROM)
712         {
713            SetLastError( ERROR_ACCESS_DENIED );
714            return FALSE;
715         }
716
717         /*
718         * FIXME: We don't return FALSE here because of differences between
719         *        Linux and Windows privileges. Under Linux only the owner of
720         *        the file is allowed to change file attributes. Under Windows,
721         *        applications expect that if you can write to a file, you can also
722         *        change its attributes (see GENERIC_WRITE). We could try to be
723         *        clever here but that would break multi-user installations where
724         *        users share read-only DLLs. This is because some installers like
725         *        to change attributes of already installed DLLs.
726         */
727         FIXME("Couldn't set file attributes for existing file \"%s\".\n"
728               "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
729     }
730     return TRUE;
731 }
732
733
734 /**************************************************************************
735  *              SetFileAttributesA      (KERNEL32.@)
736  */
737 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
738 {
739     UNICODE_STRING filenameW;
740     BOOL ret = FALSE;
741
742     if (!lpFileName)
743     {
744         SetLastError( ERROR_INVALID_PARAMETER );
745         return FALSE;
746     }
747
748     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
749     {
750         ret = SetFileAttributesW(filenameW.Buffer, attributes);
751         RtlFreeUnicodeString(&filenameW);
752     }
753     else
754         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
755     return ret;
756 }
757
758
759 /******************************************************************************
760  * GetCompressedFileSizeA [KERNEL32.@]
761  */
762 DWORD WINAPI GetCompressedFileSizeA(
763     LPCSTR lpFileName,
764     LPDWORD lpFileSizeHigh)
765 {
766     UNICODE_STRING filenameW;
767     DWORD ret;
768
769     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName))
770     {
771         ret = GetCompressedFileSizeW(filenameW.Buffer, lpFileSizeHigh);
772         RtlFreeUnicodeString(&filenameW);
773     }
774     else
775     {
776         ret = INVALID_FILE_SIZE;
777         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
778     }
779     return ret;
780 }
781
782
783 /******************************************************************************
784  * GetCompressedFileSizeW [KERNEL32.@]
785  *
786  * RETURNS
787  *    Success: Low-order doubleword of number of bytes
788  *    Failure: INVALID_FILE_SIZE
789  */
790 DWORD WINAPI GetCompressedFileSizeW(
791     LPCWSTR lpFileName,     /* [in]  Pointer to name of file */
792     LPDWORD lpFileSizeHigh) /* [out] Receives high-order doubleword of size */
793 {
794     DOS_FULL_NAME full_name;
795     struct stat st;
796     DWORD low;
797
798     TRACE("(%s,%p)\n",debugstr_w(lpFileName),lpFileSizeHigh);
799
800     if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return INVALID_FILE_SIZE;
801     if (stat(full_name.long_name, &st) != 0)
802     {
803         FILE_SetDosError();
804         return INVALID_FILE_SIZE;
805     }
806 #if HAVE_STRUCT_STAT_ST_BLOCKS
807     /* blocks are 512 bytes long */
808     if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_blocks >> 23);
809     low = (DWORD)(st.st_blocks << 9);
810 #else
811     if (lpFileSizeHigh) *lpFileSizeHigh = (st.st_size >> 32);
812     low = (DWORD)st.st_size;
813 #endif
814     return low;
815 }
816
817
818 /***********************************************************************
819  *           GetFileTime   (KERNEL32.@)
820  */
821 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
822                            FILETIME *lpLastAccessTime,
823                            FILETIME *lpLastWriteTime )
824 {
825     BY_HANDLE_FILE_INFORMATION info;
826     if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
827     if (lpCreationTime)   *lpCreationTime   = info.ftCreationTime;
828     if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
829     if (lpLastWriteTime)  *lpLastWriteTime  = info.ftLastWriteTime;
830     return TRUE;
831 }
832
833
834 /***********************************************************************
835  *           GetTempFileNameA   (KERNEL32.@)
836  */
837 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
838                                   LPSTR buffer)
839 {
840     UNICODE_STRING pathW, prefixW;
841     WCHAR bufferW[MAX_PATH];
842     UINT ret;
843
844     if ( !path || !prefix || !buffer )
845     {
846         SetLastError( ERROR_INVALID_PARAMETER );
847         return 0;
848     }
849
850     RtlCreateUnicodeStringFromAsciiz(&pathW, path);
851     RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix);
852
853     ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW);
854     if (ret)
855         WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
856
857     RtlFreeUnicodeString(&pathW);
858     RtlFreeUnicodeString(&prefixW);
859     return ret;
860 }
861
862 /***********************************************************************
863  *           GetTempFileNameW   (KERNEL32.@)
864  */
865 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
866                                   LPWSTR buffer )
867 {
868     static const WCHAR formatW[] = {'%','x','.','t','m','p',0};
869
870     DOS_FULL_NAME full_name;
871     int i;
872     LPWSTR p;
873
874     if ( !path || !prefix || !buffer )
875     {
876         SetLastError( ERROR_INVALID_PARAMETER );
877         return 0;
878     }
879
880     strcpyW( buffer, path );
881     p = buffer + strlenW(buffer);
882
883     /* add a \, if there isn't one  */
884     if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
885
886     for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
887
888     unique &= 0xffff;
889
890     if (unique) sprintfW( p, formatW, unique );
891     else
892     {
893         /* get a "random" unique number and try to create the file */
894         HANDLE handle;
895         UINT num = GetTickCount() & 0xffff;
896
897         if (!num) num = 1;
898         unique = num;
899         do
900         {
901             sprintfW( p, formatW, unique );
902             handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
903                                   CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
904             if (handle != INVALID_HANDLE_VALUE)
905             {  /* We created it */
906                 TRACE("created %s\n", debugstr_w(buffer) );
907                 CloseHandle( handle );
908                 break;
909             }
910             if (GetLastError() != ERROR_FILE_EXISTS &&
911                 GetLastError() != ERROR_SHARING_VIOLATION)
912                 break;  /* No need to go on */
913             if (!(++unique & 0xffff)) unique = 1;
914         } while (unique != num);
915     }
916
917     /* Get the full path name */
918
919     if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
920     {
921         char *slash;
922         /* Check if we have write access in the directory */
923         if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0';
924         if (access( full_name.long_name, W_OK ) == -1)
925             WARN("returns %s, which doesn't seem to be writeable.\n",
926                   debugstr_w(buffer) );
927     }
928     TRACE("returning %s\n", debugstr_w(buffer) );
929     return unique;
930 }
931
932
933 /***********************************************************************
934  *           FILE_DoOpenFile
935  *
936  * Implementation of OpenFile16() and OpenFile32().
937  */
938 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, BOOL win32 )
939 {
940     HFILE hFileRet;
941     HANDLE handle;
942     FILETIME filetime;
943     WORD filedatetime[2];
944     DOS_FULL_NAME full_name;
945     DWORD access, sharing;
946     WCHAR *p;
947     WCHAR buffer[MAX_PATH];
948     LPWSTR nameW;
949
950     if (!ofs) return HFILE_ERROR;
951
952     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
953           ((mode & 0x3 )==OF_READ)?"OF_READ":
954           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
955           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
956           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
957           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
958           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
959           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
960           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
961           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
962           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
963           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
964           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
965           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
966           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
967           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
968           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
969           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
970           );
971
972
973     ofs->cBytes = sizeof(OFSTRUCT);
974     ofs->nErrCode = 0;
975     if (mode & OF_REOPEN) name = ofs->szPathName;
976
977     if (!name) {
978         ERR("called with `name' set to NULL ! Please debug.\n");
979         return HFILE_ERROR;
980     }
981
982     TRACE("%s %04x\n", name, mode );
983
984     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
985        Are there any cases where getting the path here is wrong?
986        Uwe Bonnes 1997 Apr 2 */
987     if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
988                              ofs->szPathName, NULL )) goto error;
989     FILE_ConvertOFMode( mode, &access, &sharing );
990
991     /* OF_PARSE simply fills the structure */
992
993     if (mode & OF_PARSE)
994     {
995         ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
996                            != DRIVE_REMOVABLE);
997         TRACE("(%s): OF_PARSE, res = '%s'\n",
998                       name, ofs->szPathName );
999         return 0;
1000     }
1001
1002     /* OF_CREATE is completely different from all other options, so
1003        handle it first */
1004
1005     if (mode & OF_CREATE)
1006     {
1007         if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1008                                    sharing, NULL, CREATE_ALWAYS,
1009                                    FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1010             goto error;
1011         goto success;
1012     }
1013
1014     MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH);
1015     nameW = buffer;
1016
1017     /* If OF_SEARCH is set, ignore the given path */
1018
1019     if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1020     {
1021         /* First try the file name as is */
1022         if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found;
1023         /* Now remove the path */
1024         if (nameW[0] && (nameW[1] == ':')) nameW += 2;
1025         if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1;
1026         if ((p = strrchrW( nameW, '/' ))) nameW = p + 1;
1027         if (!nameW[0]) goto not_found;
1028     }
1029
1030     /* Now look for the file */
1031
1032     if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found;
1033
1034 found:
1035     TRACE("found %s = %s\n",
1036           full_name.long_name, debugstr_w(full_name.short_name) );
1037     WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1,
1038                         ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL);
1039
1040     if (mode & OF_DELETE)
1041     {
1042         handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1043                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
1044                                  GetDriveTypeW( full_name.short_name ) );
1045         if (!handle) goto error;
1046         CloseHandle( handle );
1047         if (unlink( full_name.long_name ) == -1) goto not_found;
1048         TRACE("(%s): OF_DELETE return = OK\n", name);
1049         return 1;
1050     }
1051
1052     handle = FILE_CreateFile( full_name.long_name, access, sharing,
1053                                 NULL, OPEN_EXISTING, 0, 0,
1054                                 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1055                                 GetDriveTypeW( full_name.short_name ) );
1056     if (!handle) goto not_found;
1057
1058     GetFileTime( handle, NULL, NULL, &filetime );
1059     FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1060     if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1061     {
1062         if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1063         {
1064             CloseHandle( handle );
1065             WARN("(%s): OF_VERIFY failed\n", name );
1066             /* FIXME: what error here? */
1067             SetLastError( ERROR_FILE_NOT_FOUND );
1068             goto error;
1069         }
1070     }
1071     ofs->Reserved1 = filedatetime[0];
1072     ofs->Reserved2 = filedatetime[1];
1073
1074 success:  /* We get here if the open was successful */
1075     TRACE("(%s): OK, return = %p\n", name, handle );
1076     if (win32)
1077     {
1078         hFileRet = (HFILE)handle;
1079         if (mode & OF_EXIST) /* Return the handle, but close it first */
1080             CloseHandle( handle );
1081     }
1082     else
1083     {
1084         hFileRet = Win32HandleToDosFileHandle( handle );
1085         if (hFileRet == HFILE_ERROR16) goto error;
1086         if (mode & OF_EXIST) /* Return the handle, but close it first */
1087             _lclose16( hFileRet );
1088     }
1089     return hFileRet;
1090
1091 not_found:  /* We get here if the file does not exist */
1092     WARN("'%s' not found or sharing violation\n", name );
1093     SetLastError( ERROR_FILE_NOT_FOUND );
1094     /* fall through */
1095
1096 error:  /* We get here if there was an error opening the file */
1097     ofs->nErrCode = GetLastError();
1098     WARN("(%s): return = HFILE_ERROR error= %d\n",
1099                   name,ofs->nErrCode );
1100     return HFILE_ERROR;
1101 }
1102
1103
1104 /***********************************************************************
1105  *           OpenFile   (KERNEL.74)
1106  *           OpenFileEx (KERNEL.360)
1107  */
1108 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1109 {
1110     return FILE_DoOpenFile( name, ofs, mode, FALSE );
1111 }
1112
1113
1114 /***********************************************************************
1115  *           OpenFile   (KERNEL32.@)
1116  */
1117 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1118 {
1119     return FILE_DoOpenFile( name, ofs, mode, TRUE );
1120 }
1121
1122
1123 /******************************************************************
1124  *              FILE_ReadWriteApc (internal)
1125  *
1126  *
1127  */
1128 static void WINAPI      FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1129 {
1130     LPOVERLAPPED_COMPLETION_ROUTINE  cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1131
1132     cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1133 }
1134
1135 /***********************************************************************
1136  *              ReadFileEx                (KERNEL32.@)
1137  */
1138 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1139                        LPOVERLAPPED overlapped,
1140                        LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1141 {
1142     LARGE_INTEGER       offset;
1143     NTSTATUS            status;
1144     PIO_STATUS_BLOCK    io_status;
1145
1146     if (!overlapped)
1147     {
1148         SetLastError(ERROR_INVALID_PARAMETER);
1149         return FALSE;
1150     }
1151
1152     offset.u.LowPart = overlapped->Offset;
1153     offset.u.HighPart = overlapped->OffsetHigh;
1154     io_status = (PIO_STATUS_BLOCK)overlapped;
1155     io_status->u.Status = STATUS_PENDING;
1156
1157     status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1158                         io_status, buffer, bytesToRead, &offset, NULL);
1159
1160     if (status)
1161     {
1162         SetLastError( RtlNtStatusToDosError(status) );
1163         return FALSE;
1164     }
1165     return TRUE;
1166 }
1167
1168 /***********************************************************************
1169  *              ReadFile                (KERNEL32.@)
1170  */
1171 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1172                       LPDWORD bytesRead, LPOVERLAPPED overlapped )
1173 {
1174     LARGE_INTEGER       offset;
1175     PLARGE_INTEGER      poffset = NULL;
1176     IO_STATUS_BLOCK     iosb;
1177     PIO_STATUS_BLOCK    io_status = &iosb;
1178     HANDLE              hEvent = 0;
1179     NTSTATUS            status;
1180         
1181     TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1182           bytesRead, overlapped );
1183
1184     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
1185     if (!bytesToRead) return TRUE;
1186
1187     if (IsBadReadPtr(buffer, bytesToRead))
1188     {
1189         SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1190         return FALSE;
1191     }
1192     if (is_console_handle(hFile))
1193         return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
1194
1195     if (overlapped != NULL)
1196     {
1197         offset.u.LowPart = overlapped->Offset;
1198         offset.u.HighPart = overlapped->OffsetHigh;
1199         poffset = &offset;
1200         hEvent = overlapped->hEvent;
1201         io_status = (PIO_STATUS_BLOCK)overlapped;
1202     }
1203     io_status->u.Status = STATUS_PENDING;
1204     io_status->Information = 0;
1205
1206     status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1207
1208     if (status != STATUS_PENDING && bytesRead)
1209         *bytesRead = io_status->Information;
1210
1211     if (status && status != STATUS_END_OF_FILE)
1212     {
1213         SetLastError( RtlNtStatusToDosError(status) );
1214         return FALSE;
1215     }
1216     return TRUE;
1217 }
1218
1219
1220 /***********************************************************************
1221  *              WriteFileEx                (KERNEL32.@)
1222  */
1223 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1224                         LPOVERLAPPED overlapped,
1225                         LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1226 {
1227     LARGE_INTEGER       offset;
1228     NTSTATUS            status;
1229     PIO_STATUS_BLOCK    io_status;
1230
1231     TRACE("%p %p %ld %p %p\n", 
1232           hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1233
1234     if (overlapped == NULL)
1235     {
1236         SetLastError(ERROR_INVALID_PARAMETER);
1237         return FALSE;
1238     }
1239     offset.u.LowPart = overlapped->Offset;
1240     offset.u.HighPart = overlapped->OffsetHigh;
1241
1242     io_status = (PIO_STATUS_BLOCK)overlapped;
1243     io_status->u.Status = STATUS_PENDING;
1244
1245     status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1246                          io_status, buffer, bytesToWrite, &offset, NULL);
1247
1248     if (status) SetLastError( RtlNtStatusToDosError(status) );
1249     return !status;
1250 }
1251
1252 /***********************************************************************
1253  *             WriteFile               (KERNEL32.@)
1254  */
1255 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1256                        LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1257 {
1258     HANDLE hEvent = NULL;
1259     LARGE_INTEGER offset;
1260     PLARGE_INTEGER poffset = NULL;
1261     NTSTATUS status;
1262     IO_STATUS_BLOCK iosb;
1263     PIO_STATUS_BLOCK piosb = &iosb;
1264
1265     TRACE("%p %p %ld %p %p\n", 
1266           hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1267
1268     if (is_console_handle(hFile))
1269         return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1270
1271     if (IsBadReadPtr(buffer, bytesToWrite))
1272     {
1273         SetLastError(ERROR_READ_FAULT); /* FIXME */
1274         return FALSE;
1275     }
1276
1277     if (overlapped)
1278     {
1279         offset.u.LowPart = overlapped->Offset;
1280         offset.u.HighPart = overlapped->OffsetHigh;
1281         poffset = &offset;
1282         hEvent = overlapped->hEvent;
1283         piosb = (PIO_STATUS_BLOCK)overlapped;
1284     }
1285     piosb->u.Status = STATUS_PENDING;
1286     piosb->Information = 0;
1287
1288     status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1289                          buffer, bytesToWrite, poffset, NULL);
1290     if (status)
1291     {
1292         SetLastError( RtlNtStatusToDosError(status) );
1293         return FALSE;
1294     }
1295     if (bytesWritten) *bytesWritten = piosb->Information;
1296
1297     return TRUE;
1298 }
1299
1300
1301 /***********************************************************************
1302  *           SetFilePointer   (KERNEL32.@)
1303  */
1304 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1305                              DWORD method )
1306 {
1307     DWORD ret = INVALID_SET_FILE_POINTER;
1308
1309     TRACE("handle %p offset %ld high %ld origin %ld\n",
1310           hFile, distance, highword?*highword:0, method );
1311
1312     SERVER_START_REQ( set_file_pointer )
1313     {
1314         req->handle = hFile;
1315         req->low = distance;
1316         req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1317         /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1318         req->whence = method;
1319         SetLastError( 0 );
1320         if (!wine_server_call_err( req ))
1321         {
1322             ret = reply->new_low;
1323             if (highword) *highword = reply->new_high;
1324         }
1325     }
1326     SERVER_END_REQ;
1327     return ret;
1328 }
1329
1330
1331 /*************************************************************************
1332  *           SetHandleCount   (KERNEL32.@)
1333  */
1334 UINT WINAPI SetHandleCount( UINT count )
1335 {
1336     return min( 256, count );
1337 }
1338
1339
1340 /**************************************************************************
1341  *           SetEndOfFile   (KERNEL32.@)
1342  */
1343 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1344 {
1345     BOOL ret;
1346     SERVER_START_REQ( truncate_file )
1347     {
1348         req->handle = hFile;
1349         ret = !wine_server_call_err( req );
1350     }
1351     SERVER_END_REQ;
1352     return ret;
1353 }
1354
1355
1356 /***********************************************************************
1357  *           DeleteFileW   (KERNEL32.@)
1358  */
1359 BOOL WINAPI DeleteFileW( LPCWSTR path )
1360 {
1361     DOS_FULL_NAME full_name;
1362     HANDLE hFile;
1363
1364     TRACE("%s\n", debugstr_w(path) );
1365     if (!path || !*path)
1366     {
1367         SetLastError(ERROR_PATH_NOT_FOUND);
1368         return FALSE;
1369     }
1370     if (RtlIsDosDeviceName_U( path ))
1371     {
1372         WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1373         SetLastError( ERROR_FILE_NOT_FOUND );
1374         return FALSE;
1375     }
1376
1377     if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1378
1379     /* check if we are allowed to delete the source */
1380     hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1381                              NULL, OPEN_EXISTING, 0, 0, TRUE,
1382                              GetDriveTypeW( full_name.short_name ) );
1383     if (!hFile) return FALSE;
1384
1385     if (unlink( full_name.long_name ) == -1)
1386     {
1387         FILE_SetDosError();
1388         CloseHandle(hFile);
1389         return FALSE;
1390     }
1391     CloseHandle(hFile);
1392     return TRUE;
1393 }
1394
1395
1396 /***********************************************************************
1397  *           DeleteFileA   (KERNEL32.@)
1398  */
1399 BOOL WINAPI DeleteFileA( LPCSTR path )
1400 {
1401     UNICODE_STRING pathW;
1402     BOOL ret = FALSE;
1403
1404     if (!path)
1405     {
1406         SetLastError(ERROR_INVALID_PARAMETER);
1407         return FALSE;
1408     }
1409
1410     if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1411     {
1412         ret = DeleteFileW(pathW.Buffer);
1413         RtlFreeUnicodeString(&pathW);
1414     }
1415     else
1416         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1417     return ret;
1418 }
1419
1420
1421 /***********************************************************************
1422  *           GetFileType   (KERNEL32.@)
1423  */
1424 DWORD WINAPI GetFileType( HANDLE hFile )
1425 {
1426     DWORD ret = FILE_TYPE_UNKNOWN;
1427
1428     if (is_console_handle( hFile ))
1429         return FILE_TYPE_CHAR;
1430
1431     SERVER_START_REQ( get_file_info )
1432     {
1433         req->handle = hFile;
1434         if (!wine_server_call_err( req )) ret = reply->type;
1435     }
1436     SERVER_END_REQ;
1437     return ret;
1438 }
1439
1440
1441 /* check if a file name is for an executable file (.exe or .com) */
1442 inline static BOOL is_executable( const char *name )
1443 {
1444     int len = strlen(name);
1445
1446     if (len < 4) return FALSE;
1447     return (!strcasecmp( name + len - 4, ".exe" ) ||
1448             !strcasecmp( name + len - 4, ".com" ));
1449 }
1450
1451
1452 /***********************************************************************
1453  *           FILE_AddBootRenameEntry
1454  *
1455  * Adds an entry to the registry that is loaded when windows boots and
1456  * checks if there are some files to be removed or renamed/moved.
1457  * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1458  * non-NULL then the file is moved, otherwise it is deleted.  The
1459  * entry of the registrykey is always appended with two zero
1460  * terminated strings. If <fn2> is NULL then the second entry is
1461  * simply a single 0-byte. Otherwise the second filename goes
1462  * there. The entries are prepended with \??\ before the path and the
1463  * second filename gets also a '!' as the first character if
1464  * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1465  * 0-byte follows to indicate the end of the strings.
1466  * i.e.:
1467  * \??\D:\test\file1[0]
1468  * !\??\D:\test\file1_renamed[0]
1469  * \??\D:\Test|delete[0]
1470  * [0]                        <- file is to be deleted, second string empty
1471  * \??\D:\test\file2[0]
1472  * !\??\D:\test\file2_renamed[0]
1473  * [0]                        <- indicates end of strings
1474  *
1475  * or:
1476  * \??\D:\test\file1[0]
1477  * !\??\D:\test\file1_renamed[0]
1478  * \??\D:\Test|delete[0]
1479  * [0]                        <- file is to be deleted, second string empty
1480  * [0]                        <- indicates end of strings
1481  *
1482  */
1483 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1484 {
1485     static const WCHAR PreString[] = {'\\','?','?','\\',0};
1486     static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1487                                       'F','i','l','e','R','e','n','a','m','e',
1488                                       'O','p','e','r','a','t','i','o','n','s',0};
1489     static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1490                                      'S','y','s','t','e','m','\\',
1491                                      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1492                                      'C','o','n','t','r','o','l','\\',
1493                                      'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1494     static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1495
1496     OBJECT_ATTRIBUTES attr;
1497     UNICODE_STRING nameW;
1498     KEY_VALUE_PARTIAL_INFORMATION *info;
1499     BOOL rc = FALSE;
1500     HKEY Reboot = 0;
1501     DWORD len0, len1, len2;
1502     DWORD DataSize = 0;
1503     BYTE *Buffer = NULL;
1504     WCHAR *p;
1505
1506     attr.Length = sizeof(attr);
1507     attr.RootDirectory = 0;
1508     attr.ObjectName = &nameW;
1509     attr.Attributes = 0;
1510     attr.SecurityDescriptor = NULL;
1511     attr.SecurityQualityOfService = NULL;
1512     RtlInitUnicodeString( &nameW, SessionW );
1513
1514     if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1515     {
1516         WARN("Error creating key for reboot managment [%s]\n",
1517              "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1518         return FALSE;
1519     }
1520
1521     len0 = strlenW(PreString);
1522     len1 = strlenW(fn1) + len0 + 1;
1523     if (fn2)
1524     {
1525         len2 = strlenW(fn2) + len0 + 1;
1526         if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1527     }
1528     else len2 = 1; /* minimum is the 0 characters for the empty second string */
1529
1530     /* convert characters to bytes */
1531     len0 *= sizeof(WCHAR);
1532     len1 *= sizeof(WCHAR);
1533     len2 *= sizeof(WCHAR);
1534
1535     RtlInitUnicodeString( &nameW, ValueName );
1536
1537     /* First we check if the key exists and if so how many bytes it already contains. */
1538     if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1539                          NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1540     {
1541         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1542             goto Quit;
1543         if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1544                              Buffer, DataSize, &DataSize )) goto Quit;
1545         info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1546         if (info->Type != REG_MULTI_SZ) goto Quit;
1547         if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR);  /* remove terminating null (will be added back later) */
1548     }
1549     else
1550     {
1551         DataSize = info_size;
1552         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1553             goto Quit;
1554     }
1555
1556     p = (WCHAR *)(Buffer + DataSize);
1557     strcpyW( p, PreString );
1558     strcatW( p, fn1 );
1559     DataSize += len1;
1560     if (fn2)
1561     {
1562         p = (WCHAR *)(Buffer + DataSize);
1563         if (flags & MOVEFILE_REPLACE_EXISTING)
1564             *p++ = '!';
1565         strcpyW( p, PreString );
1566         strcatW( p, fn2 );
1567         DataSize += len2;
1568     }
1569     else
1570     {
1571         p = (WCHAR *)(Buffer + DataSize);
1572         *p = 0;
1573         DataSize += sizeof(WCHAR);
1574     }
1575
1576     /* add final null */
1577     p = (WCHAR *)(Buffer + DataSize);
1578     *p = 0;
1579     DataSize += sizeof(WCHAR);
1580
1581     rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1582
1583  Quit:
1584     if (Reboot) NtClose(Reboot);
1585     if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1586     return(rc);
1587 }
1588
1589
1590 /**************************************************************************
1591  *           MoveFileExW   (KERNEL32.@)
1592  */
1593 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1594 {
1595     DOS_FULL_NAME full_name1, full_name2;
1596     HANDLE hFile;
1597     DWORD attr = INVALID_FILE_ATTRIBUTES;
1598
1599     TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1600
1601     /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1602        In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1603        to be really compatible. Most programs won't have any problems though. In case
1604        you encounter one, this is what you should return here. I don't know what's up
1605        with NT 3.5. Is this function available there or not?
1606        Does anybody really care about 3.5? :)
1607     */
1608
1609     /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1610        if the source file has to be deleted.
1611     */
1612     if (!fn1) {
1613         SetLastError(ERROR_INVALID_PARAMETER);
1614         return FALSE;
1615     }
1616
1617     /* This function has to be run through in order to process the name properly.
1618        If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1619        that is the behaviour on NT 4.0. The operation accepts the filenames as
1620        they are given but it can't reply with a reasonable returncode. Success
1621        means in that case success for entering the values into the registry.
1622     */
1623     if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1624     {
1625         if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1626             return FALSE;
1627     }
1628
1629     if (fn2)  /* !fn2 means delete fn1 */
1630     {
1631         if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1632         {
1633             if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1634             {
1635                 /* target exists, check if we may overwrite */
1636                 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1637                 {
1638                     SetLastError( ERROR_ALREADY_EXISTS );
1639                     return FALSE;
1640                 }
1641             }
1642         }
1643         else
1644         {
1645             if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1646             {
1647                 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1648                     return FALSE;
1649             }
1650         }
1651
1652         /* Source name and target path are valid */
1653
1654         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1655         {
1656             return FILE_AddBootRenameEntry( fn1, fn2, flag );
1657         }
1658
1659         attr = GetFileAttributesW( fn1 );
1660         if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1661
1662         /* check if we are allowed to rename the source */
1663         hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1664                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
1665                                  GetDriveTypeW( full_name1.short_name ) );
1666         if (!hFile)
1667         {
1668             if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1669             if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1670             /* if it's a directory we can continue */
1671         }
1672         else CloseHandle(hFile);
1673
1674         /* check, if we are allowed to delete the destination,
1675         **     (but the file not being there is fine) */
1676         hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1677                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
1678                                  GetDriveTypeW( full_name2.short_name ) );
1679         if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
1680         CloseHandle(hFile);
1681
1682         if (full_name1.drive != full_name2.drive)
1683         {
1684             if (!(flag & MOVEFILE_COPY_ALLOWED))
1685             {
1686                 SetLastError( ERROR_NOT_SAME_DEVICE );
1687                 return FALSE;
1688             }
1689             else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1690             {
1691                 /* Strange, but that's what Windows returns */
1692                 SetLastError ( ERROR_ACCESS_DENIED );
1693                 return FALSE;
1694             }
1695         }
1696         if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1697             /* Try copy/delete unless it's a directory. */
1698             /* FIXME: This does not handle the (unlikely) case that the two locations
1699                are on the same Wine drive, but on different Unix file systems. */
1700         {
1701             if ( attr & FILE_ATTRIBUTE_DIRECTORY )
1702             {
1703                 FILE_SetDosError();
1704                 return FALSE;
1705             }
1706             else
1707             {
1708                 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
1709                     return FALSE;
1710                 if ( ! DeleteFileW ( fn1 ) )
1711                     return FALSE;
1712             }
1713         }
1714         if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
1715         {
1716             struct stat fstat;
1717             if (stat( full_name2.long_name, &fstat ) != -1)
1718             {
1719                 if (is_executable( full_name2.long_name ))
1720                     /* set executable bit where read bit is set */
1721                     fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
1722                 else
1723                     fstat.st_mode &= ~0111;
1724                 chmod( full_name2.long_name, fstat.st_mode );
1725             }
1726         }
1727         return TRUE;
1728     }
1729     else /* fn2 == NULL means delete source */
1730     {
1731         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1732         {
1733             if (flag & MOVEFILE_COPY_ALLOWED) {
1734                 WARN("Illegal flag\n");
1735                 SetLastError( ERROR_GEN_FAILURE );
1736                 return FALSE;
1737             }
1738
1739             return FILE_AddBootRenameEntry( fn1, NULL, flag );
1740         }
1741
1742         if (unlink( full_name1.long_name ) == -1)
1743         {
1744             FILE_SetDosError();
1745             return FALSE;
1746         }
1747         return TRUE; /* successfully deleted */
1748     }
1749 }
1750
1751 /**************************************************************************
1752  *           MoveFileExA   (KERNEL32.@)
1753  */
1754 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
1755 {
1756     UNICODE_STRING fn1W, fn2W;
1757     BOOL ret;
1758
1759     if (!fn1)
1760     {
1761         SetLastError(ERROR_INVALID_PARAMETER);
1762         return FALSE;
1763     }
1764
1765     RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
1766     if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
1767     else fn2W.Buffer = NULL;
1768
1769     ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
1770
1771     RtlFreeUnicodeString(&fn1W);
1772     RtlFreeUnicodeString(&fn2W);
1773     return ret;
1774 }
1775
1776
1777 /**************************************************************************
1778  *           MoveFileW   (KERNEL32.@)
1779  *
1780  *  Move file or directory
1781  */
1782 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
1783 {
1784     return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1785 }
1786
1787
1788 /**************************************************************************
1789  *           MoveFileA   (KERNEL32.@)
1790  */
1791 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
1792 {
1793     return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
1794 }
1795
1796
1797 /**************************************************************************
1798  *           CopyFileW   (KERNEL32.@)
1799  */
1800 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
1801 {
1802     HANDLE h1, h2;
1803     BY_HANDLE_FILE_INFORMATION info;
1804     DWORD count;
1805     BOOL ret = FALSE;
1806     char buffer[2048];
1807
1808     if (!source || !dest)
1809     {
1810         SetLastError(ERROR_INVALID_PARAMETER);
1811         return FALSE;
1812     }
1813
1814     TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
1815
1816     if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
1817                      NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
1818     {
1819         WARN("Unable to open source %s\n", debugstr_w(source));
1820         return FALSE;
1821     }
1822
1823     if (!GetFileInformationByHandle( h1, &info ))
1824     {
1825         WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
1826         CloseHandle( h1 );
1827         return FALSE;
1828     }
1829
1830     if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1831                              fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
1832                              info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
1833     {
1834         WARN("Unable to open dest %s\n", debugstr_w(dest));
1835         CloseHandle( h1 );
1836         return FALSE;
1837     }
1838
1839     while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
1840     {
1841         char *p = buffer;
1842         while (count != 0)
1843         {
1844             DWORD res;
1845             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
1846             p += res;
1847             count -= res;
1848         }
1849     }
1850     ret =  TRUE;
1851 done:
1852     CloseHandle( h1 );
1853     CloseHandle( h2 );
1854     return ret;
1855 }
1856
1857
1858 /**************************************************************************
1859  *           CopyFileA   (KERNEL32.@)
1860  */
1861 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
1862 {
1863     UNICODE_STRING sourceW, destW;
1864     BOOL ret;
1865
1866     if (!source || !dest)
1867     {
1868         SetLastError(ERROR_INVALID_PARAMETER);
1869         return FALSE;
1870     }
1871
1872     RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
1873     RtlCreateUnicodeStringFromAsciiz(&destW, dest);
1874
1875     ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
1876
1877     RtlFreeUnicodeString(&sourceW);
1878     RtlFreeUnicodeString(&destW);
1879     return ret;
1880 }
1881
1882
1883 /**************************************************************************
1884  *           CopyFileExW   (KERNEL32.@)
1885  *
1886  * This implementation ignores most of the extra parameters passed-in into
1887  * the "ex" version of the method and calls the CopyFile method.
1888  * It will have to be fixed eventually.
1889  */
1890 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
1891                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1892                         LPBOOL cancelFlagPointer, DWORD copyFlags)
1893 {
1894     /*
1895      * Interpret the only flag that CopyFile can interpret.
1896      */
1897     return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
1898 }
1899
1900
1901 /**************************************************************************
1902  *           CopyFileExA   (KERNEL32.@)
1903  */
1904 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
1905                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
1906                         LPBOOL cancelFlagPointer, DWORD copyFlags)
1907 {
1908     UNICODE_STRING sourceW, destW;
1909     BOOL ret;
1910
1911     if (!sourceFilename || !destFilename)
1912     {
1913         SetLastError(ERROR_INVALID_PARAMETER);
1914         return FALSE;
1915     }
1916
1917     RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
1918     RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
1919
1920     ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
1921                       cancelFlagPointer, copyFlags);
1922
1923     RtlFreeUnicodeString(&sourceW);
1924     RtlFreeUnicodeString(&destW);
1925     return ret;
1926 }
1927
1928
1929 /***********************************************************************
1930  *              SetFileTime   (KERNEL32.@)
1931  */
1932 BOOL WINAPI SetFileTime( HANDLE hFile,
1933                            const FILETIME *lpCreationTime,
1934                            const FILETIME *lpLastAccessTime,
1935                            const FILETIME *lpLastWriteTime )
1936 {
1937     BOOL ret;
1938     SERVER_START_REQ( set_file_time )
1939     {
1940         req->handle = hFile;
1941         if (lpLastAccessTime)
1942             RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
1943         else
1944             req->access_time = 0; /* FIXME */
1945         if (lpLastWriteTime)
1946             RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
1947         else
1948             req->write_time = 0; /* FIXME */
1949         ret = !wine_server_call_err( req );
1950     }
1951     SERVER_END_REQ;
1952     return ret;
1953 }
1954
1955
1956 /**************************************************************************
1957  *           GetFileAttributesExW   (KERNEL32.@)
1958  */
1959 BOOL WINAPI GetFileAttributesExW(
1960         LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1961         LPVOID lpFileInformation)
1962 {
1963     DOS_FULL_NAME full_name;
1964     BY_HANDLE_FILE_INFORMATION info;
1965
1966     if (!lpFileName || !lpFileInformation)
1967     {
1968         SetLastError(ERROR_INVALID_PARAMETER);
1969         return FALSE;
1970     }
1971
1972     if (fInfoLevelId == GetFileExInfoStandard) {
1973         LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
1974             (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
1975         if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
1976         if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
1977
1978         lpFad->dwFileAttributes = info.dwFileAttributes;
1979         lpFad->ftCreationTime   = info.ftCreationTime;
1980         lpFad->ftLastAccessTime = info.ftLastAccessTime;
1981         lpFad->ftLastWriteTime  = info.ftLastWriteTime;
1982         lpFad->nFileSizeHigh    = info.nFileSizeHigh;
1983         lpFad->nFileSizeLow     = info.nFileSizeLow;
1984     }
1985     else {
1986         FIXME("invalid info level %d!\n", fInfoLevelId);
1987         return FALSE;
1988     }
1989
1990     return TRUE;
1991 }
1992
1993
1994 /**************************************************************************
1995  *           GetFileAttributesExA   (KERNEL32.@)
1996  */
1997 BOOL WINAPI GetFileAttributesExA(
1998         LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
1999         LPVOID lpFileInformation)
2000 {
2001     UNICODE_STRING filenameW;
2002     BOOL ret = FALSE;
2003
2004     if (!filename || !lpFileInformation)
2005     {
2006         SetLastError(ERROR_INVALID_PARAMETER);
2007         return FALSE;
2008     }
2009
2010     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2011     {
2012         ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2013         RtlFreeUnicodeString(&filenameW);
2014     }
2015     else
2016         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2017     return ret;
2018 }