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