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