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