Cast time_t to long for printing.
[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_DELETE)
1225     {
1226         handle = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1227                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
1228                                  GetDriveTypeW( full_name.short_name ) );
1229         if (!handle) goto error;
1230         CloseHandle( handle );
1231         if (unlink( full_name.long_name ) == -1) goto not_found;
1232         TRACE("(%s): OF_DELETE return = OK\n", name);
1233         return 1;
1234     }
1235
1236     handle = FILE_CreateFile( full_name.long_name, access, sharing,
1237                                 NULL, OPEN_EXISTING, 0, 0,
1238                                 DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1239                                 GetDriveTypeW( full_name.short_name ) );
1240     if (!handle) goto not_found;
1241
1242     GetFileTime( handle, NULL, NULL, &filetime );
1243     FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1244     if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1245     {
1246         if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1247         {
1248             CloseHandle( handle );
1249             WARN("(%s): OF_VERIFY failed\n", name );
1250             /* FIXME: what error here? */
1251             SetLastError( ERROR_FILE_NOT_FOUND );
1252             goto error;
1253         }
1254     }
1255     ofs->Reserved1 = filedatetime[0];
1256     ofs->Reserved2 = filedatetime[1];
1257
1258 success:  /* We get here if the open was successful */
1259     TRACE("(%s): OK, return = %p\n", name, handle );
1260     if (win32)
1261     {
1262         hFileRet = (HFILE)handle;
1263         if (mode & OF_EXIST) /* Return the handle, but close it first */
1264             CloseHandle( handle );
1265     }
1266     else
1267     {
1268         hFileRet = Win32HandleToDosFileHandle( handle );
1269         if (hFileRet == HFILE_ERROR16) goto error;
1270         if (mode & OF_EXIST) /* Return the handle, but close it first */
1271             _lclose16( hFileRet );
1272     }
1273     return hFileRet;
1274
1275 not_found:  /* We get here if the file does not exist */
1276     WARN("'%s' not found or sharing violation\n", name );
1277     SetLastError( ERROR_FILE_NOT_FOUND );
1278     /* fall through */
1279
1280 error:  /* We get here if there was an error opening the file */
1281     ofs->nErrCode = GetLastError();
1282     WARN("(%s): return = HFILE_ERROR error= %d\n",
1283                   name,ofs->nErrCode );
1284     return HFILE_ERROR;
1285 }
1286
1287
1288 /***********************************************************************
1289  *           OpenFile   (KERNEL.74)
1290  *           OpenFileEx (KERNEL.360)
1291  */
1292 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1293 {
1294     return FILE_DoOpenFile( name, ofs, mode, FALSE );
1295 }
1296
1297
1298 /***********************************************************************
1299  *           OpenFile   (KERNEL32.@)
1300  */
1301 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1302 {
1303     return FILE_DoOpenFile( name, ofs, mode, TRUE );
1304 }
1305
1306
1307 /***********************************************************************
1308  *           FILE_InitProcessDosHandles
1309  *
1310  * Allocates the default DOS handles for a process. Called either by
1311  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1312  */
1313 static void FILE_InitProcessDosHandles( void )
1314 {
1315     HANDLE cp = GetCurrentProcess();
1316     DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1317                     0, TRUE, DUPLICATE_SAME_ACCESS);
1318     DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1319                     0, TRUE, DUPLICATE_SAME_ACCESS);
1320     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1321                     0, TRUE, DUPLICATE_SAME_ACCESS);
1322     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1323                     0, TRUE, DUPLICATE_SAME_ACCESS);
1324     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1325                     0, TRUE, DUPLICATE_SAME_ACCESS);
1326 }
1327
1328 /***********************************************************************
1329  *           Win32HandleToDosFileHandle   (KERNEL32.21)
1330  *
1331  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1332  * longer valid after this function (even on failure).
1333  *
1334  * Note: this is not exactly right, since on Win95 the Win32 handles
1335  *       are on top of DOS handles and we do it the other way
1336  *       around. Should be good enough though.
1337  */
1338 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1339 {
1340     int i;
1341
1342     if (!handle || (handle == INVALID_HANDLE_VALUE))
1343         return HFILE_ERROR;
1344
1345     for (i = 5; i < DOS_TABLE_SIZE; i++)
1346         if (!dos_handles[i])
1347         {
1348             dos_handles[i] = handle;
1349             TRACE("Got %d for h32 %p\n", i, handle );
1350             return (HFILE)i;
1351         }
1352     CloseHandle( handle );
1353     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1354     return HFILE_ERROR;
1355 }
1356
1357
1358 /***********************************************************************
1359  *           DosFileHandleToWin32Handle   (KERNEL32.20)
1360  *
1361  * Return the Win32 handle for a DOS handle.
1362  *
1363  * Note: this is not exactly right, since on Win95 the Win32 handles
1364  *       are on top of DOS handles and we do it the other way
1365  *       around. Should be good enough though.
1366  */
1367 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1368 {
1369     HFILE16 hfile = (HFILE16)handle;
1370     if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1371     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1372     {
1373         SetLastError( ERROR_INVALID_HANDLE );
1374         return INVALID_HANDLE_VALUE;
1375     }
1376     return dos_handles[hfile];
1377 }
1378
1379
1380 /***********************************************************************
1381  *           DisposeLZ32Handle   (KERNEL32.22)
1382  *
1383  * Note: this is not entirely correct, we should only close the
1384  *       32-bit handle and not the 16-bit one, but we cannot do
1385  *       this because of the way our DOS handles are implemented.
1386  *       It shouldn't break anything though.
1387  */
1388 void WINAPI DisposeLZ32Handle( HANDLE handle )
1389 {
1390     int i;
1391
1392     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1393
1394     for (i = 5; i < DOS_TABLE_SIZE; i++)
1395         if (dos_handles[i] == handle)
1396         {
1397             dos_handles[i] = 0;
1398             CloseHandle( handle );
1399             break;
1400         }
1401 }
1402
1403
1404 /***********************************************************************
1405  *           FILE_Dup2
1406  *
1407  * dup2() function for DOS handles.
1408  */
1409 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1410 {
1411     HANDLE new_handle;
1412
1413     if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1414
1415     if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1416     {
1417         SetLastError( ERROR_INVALID_HANDLE );
1418         return HFILE_ERROR16;
1419     }
1420     if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1421                           GetCurrentProcess(), &new_handle,
1422                           0, FALSE, DUPLICATE_SAME_ACCESS ))
1423         return HFILE_ERROR16;
1424     if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1425     dos_handles[hFile2] = new_handle;
1426     return hFile2;
1427 }
1428
1429
1430 /***********************************************************************
1431  *           _lclose   (KERNEL.81)
1432  */
1433 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1434 {
1435     if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1436     {
1437         SetLastError( ERROR_INVALID_HANDLE );
1438         return HFILE_ERROR16;
1439     }
1440     TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] );
1441     CloseHandle( dos_handles[hFile] );
1442     dos_handles[hFile] = 0;
1443     return 0;
1444 }
1445
1446
1447 /******************************************************************
1448  *              FILE_ReadWriteApc (internal)
1449  *
1450  *
1451  */
1452 static void WINAPI      FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len)
1453 {
1454     LPOVERLAPPED_COMPLETION_ROUTINE  cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user;
1455
1456     cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status);
1457 }
1458
1459 /***********************************************************************
1460  *              ReadFileEx                (KERNEL32.@)
1461  */
1462 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1463                        LPOVERLAPPED overlapped,
1464                        LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1465 {
1466     LARGE_INTEGER       offset;
1467     NTSTATUS            status;
1468     PIO_STATUS_BLOCK    io_status;
1469
1470     if (!overlapped)
1471     {
1472         SetLastError(ERROR_INVALID_PARAMETER);
1473         return FALSE;
1474     }
1475
1476     offset.s.LowPart = overlapped->Offset;
1477     offset.s.HighPart = overlapped->OffsetHigh;
1478     io_status = (PIO_STATUS_BLOCK)overlapped;
1479     io_status->u.Status = STATUS_PENDING;
1480
1481     status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1482                         io_status, buffer, bytesToRead, &offset, NULL);
1483
1484     if (status)
1485     {
1486         SetLastError( RtlNtStatusToDosError(status) );
1487         return FALSE;
1488     }
1489     return TRUE;
1490 }
1491
1492 /***********************************************************************
1493  *              ReadFile                (KERNEL32.@)
1494  */
1495 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1496                       LPDWORD bytesRead, LPOVERLAPPED overlapped )
1497 {
1498     LARGE_INTEGER       offset;
1499     PLARGE_INTEGER      poffset = NULL;
1500     IO_STATUS_BLOCK     iosb;
1501     PIO_STATUS_BLOCK    io_status = &iosb;
1502     HANDLE              hEvent = 0;
1503     NTSTATUS            status;
1504         
1505     TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead,
1506           bytesRead, overlapped );
1507
1508     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
1509     if (!bytesToRead) return TRUE;
1510
1511     if (IsBadReadPtr(buffer, bytesToRead))
1512     {
1513         SetLastError(ERROR_WRITE_FAULT); /* FIXME */
1514         return FALSE;
1515     }
1516     if (is_console_handle(hFile))
1517         return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1518
1519     if (overlapped != NULL)
1520     {
1521         offset.s.LowPart = overlapped->Offset;
1522         offset.s.HighPart = overlapped->OffsetHigh;
1523         poffset = &offset;
1524         hEvent = overlapped->hEvent;
1525         io_status = (PIO_STATUS_BLOCK)overlapped;
1526     }
1527     io_status->u.Status = STATUS_PENDING;
1528     io_status->Information = 0;
1529
1530     status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL);
1531
1532     if (status != STATUS_PENDING && bytesRead)
1533         *bytesRead = io_status->Information;
1534
1535     if (status && status != STATUS_END_OF_FILE)
1536     {
1537         SetLastError( RtlNtStatusToDosError(status) );
1538         return FALSE;
1539     }
1540     return TRUE;
1541 }
1542
1543
1544 /***********************************************************************
1545  *              WriteFileEx                (KERNEL32.@)
1546  */
1547 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1548                         LPOVERLAPPED overlapped,
1549                         LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1550 {
1551     LARGE_INTEGER       offset;
1552     NTSTATUS            status;
1553     PIO_STATUS_BLOCK    io_status;
1554
1555     TRACE("%p %p %ld %p %p\n", 
1556           hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
1557
1558     if (overlapped == NULL)
1559     {
1560         SetLastError(ERROR_INVALID_PARAMETER);
1561         return FALSE;
1562     }
1563     offset.s.LowPart = overlapped->Offset;
1564     offset.s.HighPart = overlapped->OffsetHigh;
1565
1566     io_status = (PIO_STATUS_BLOCK)overlapped;
1567     io_status->u.Status = STATUS_PENDING;
1568
1569     status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
1570                          io_status, buffer, bytesToWrite, &offset, NULL);
1571
1572     if (status) SetLastError( RtlNtStatusToDosError(status) );
1573     return !status;
1574 }
1575
1576 /***********************************************************************
1577  *             WriteFile               (KERNEL32.@)
1578  */
1579 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1580                        LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1581 {
1582     HANDLE hEvent = NULL;
1583     LARGE_INTEGER offset;
1584     PLARGE_INTEGER poffset = NULL;
1585     NTSTATUS status;
1586     IO_STATUS_BLOCK iosb;
1587     PIO_STATUS_BLOCK piosb = &iosb;
1588
1589     TRACE("%p %p %ld %p %p\n", 
1590           hFile, buffer, bytesToWrite, bytesWritten, overlapped );
1591
1592     if (is_console_handle(hFile))
1593         return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1594     
1595     if (IsBadReadPtr(buffer, bytesToWrite))
1596     {
1597         SetLastError(ERROR_READ_FAULT); /* FIXME */
1598         return FALSE;
1599     }
1600
1601     if (overlapped)
1602     {
1603         offset.s.LowPart = overlapped->Offset;
1604         offset.s.HighPart = overlapped->OffsetHigh;
1605         poffset = &offset;
1606         hEvent = overlapped->hEvent;
1607         piosb = (PIO_STATUS_BLOCK)overlapped;
1608     }
1609     piosb->u.Status = STATUS_PENDING;
1610     piosb->Information = 0;
1611
1612     status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb,
1613                          buffer, bytesToWrite, poffset, NULL);
1614     if (status)
1615     {
1616         SetLastError( RtlNtStatusToDosError(status) );
1617         return FALSE;
1618     }
1619     if (bytesWritten) *bytesWritten = piosb->Information;
1620
1621     return TRUE;
1622 }
1623
1624
1625 /***********************************************************************
1626  *           SetFilePointer   (KERNEL32.@)
1627  */
1628 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
1629                              DWORD method )
1630 {
1631     DWORD ret = INVALID_SET_FILE_POINTER;
1632
1633     TRACE("handle %p offset %ld high %ld origin %ld\n",
1634           hFile, distance, highword?*highword:0, method );
1635
1636     SERVER_START_REQ( set_file_pointer )
1637     {
1638         req->handle = hFile;
1639         req->low = distance;
1640         req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
1641         /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
1642         req->whence = method;
1643         SetLastError( 0 );
1644         if (!wine_server_call_err( req ))
1645         {
1646             ret = reply->new_low;
1647             if (highword) *highword = reply->new_high;
1648         }
1649     }
1650     SERVER_END_REQ;
1651     return ret;
1652 }
1653
1654
1655 /*************************************************************************
1656  *           SetHandleCount   (KERNEL32.@)
1657  */
1658 UINT WINAPI SetHandleCount( UINT count )
1659 {
1660     return min( 256, count );
1661 }
1662
1663
1664 /**************************************************************************
1665  *           SetEndOfFile   (KERNEL32.@)
1666  */
1667 BOOL WINAPI SetEndOfFile( HANDLE hFile )
1668 {
1669     BOOL ret;
1670     SERVER_START_REQ( truncate_file )
1671     {
1672         req->handle = hFile;
1673         ret = !wine_server_call_err( req );
1674     }
1675     SERVER_END_REQ;
1676     return ret;
1677 }
1678
1679
1680 /***********************************************************************
1681  *           DeleteFileW   (KERNEL32.@)
1682  */
1683 BOOL WINAPI DeleteFileW( LPCWSTR path )
1684 {
1685     DOS_FULL_NAME full_name;
1686     HANDLE hFile;
1687
1688     TRACE("%s\n", debugstr_w(path) );
1689     if (!path || !*path)
1690     {
1691         SetLastError(ERROR_PATH_NOT_FOUND);
1692         return FALSE;
1693     }
1694     if (DOSFS_GetDevice( path ))
1695     {
1696         WARN("cannot remove DOS device %s!\n", debugstr_w(path));
1697         SetLastError( ERROR_FILE_NOT_FOUND );
1698         return FALSE;
1699     }
1700
1701     if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1702
1703     /* check if we are allowed to delete the source */
1704     hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
1705                              NULL, OPEN_EXISTING, 0, 0, TRUE,
1706                              GetDriveTypeW( full_name.short_name ) );
1707     if (!hFile) return FALSE;
1708
1709     if (unlink( full_name.long_name ) == -1)
1710     {
1711         FILE_SetDosError();
1712         CloseHandle(hFile);
1713         return FALSE;
1714     }
1715     CloseHandle(hFile);
1716     return TRUE;
1717 }
1718
1719
1720 /***********************************************************************
1721  *           DeleteFileA   (KERNEL32.@)
1722  */
1723 BOOL WINAPI DeleteFileA( LPCSTR path )
1724 {
1725     UNICODE_STRING pathW;
1726     BOOL ret = FALSE;
1727
1728     if (!path)
1729     {
1730         SetLastError(ERROR_INVALID_PARAMETER);
1731         return FALSE;
1732     }
1733
1734     if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
1735     {
1736         ret = DeleteFileW(pathW.Buffer);
1737         RtlFreeUnicodeString(&pathW);
1738     }
1739     else
1740         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1741     return ret;
1742 }
1743
1744
1745 /***********************************************************************
1746  *           GetFileType   (KERNEL32.@)
1747  */
1748 DWORD WINAPI GetFileType( HANDLE hFile )
1749 {
1750     DWORD ret = FILE_TYPE_UNKNOWN;
1751
1752     if (is_console_handle( hFile ))
1753         return FILE_TYPE_CHAR;
1754
1755     SERVER_START_REQ( get_file_info )
1756     {
1757         req->handle = hFile;
1758         if (!wine_server_call_err( req )) ret = reply->type;
1759     }
1760     SERVER_END_REQ;
1761     return ret;
1762 }
1763
1764
1765 /* check if a file name is for an executable file (.exe or .com) */
1766 inline static BOOL is_executable( const char *name )
1767 {
1768     int len = strlen(name);
1769
1770     if (len < 4) return FALSE;
1771     return (!strcasecmp( name + len - 4, ".exe" ) ||
1772             !strcasecmp( name + len - 4, ".com" ));
1773 }
1774
1775
1776 /***********************************************************************
1777  *           FILE_AddBootRenameEntry
1778  *
1779  * Adds an entry to the registry that is loaded when windows boots and
1780  * checks if there are some files to be removed or renamed/moved.
1781  * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
1782  * non-NULL then the file is moved, otherwise it is deleted.  The
1783  * entry of the registrykey is always appended with two zero
1784  * terminated strings. If <fn2> is NULL then the second entry is
1785  * simply a single 0-byte. Otherwise the second filename goes
1786  * there. The entries are prepended with \??\ before the path and the
1787  * second filename gets also a '!' as the first character if
1788  * MOVEFILE_REPLACE_EXISTING is set. After the final string another
1789  * 0-byte follows to indicate the end of the strings.
1790  * i.e.:
1791  * \??\D:\test\file1[0]
1792  * !\??\D:\test\file1_renamed[0]
1793  * \??\D:\Test|delete[0]
1794  * [0]                        <- file is to be deleted, second string empty
1795  * \??\D:\test\file2[0]
1796  * !\??\D:\test\file2_renamed[0]
1797  * [0]                        <- indicates end of strings
1798  *
1799  * or:
1800  * \??\D:\test\file1[0]
1801  * !\??\D:\test\file1_renamed[0]
1802  * \??\D:\Test|delete[0]
1803  * [0]                        <- file is to be deleted, second string empty
1804  * [0]                        <- indicates end of strings
1805  *
1806  */
1807 static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags )
1808 {
1809     static const WCHAR PreString[] = {'\\','?','?','\\',0};
1810     static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
1811                                       'F','i','l','e','R','e','n','a','m','e',
1812                                       'O','p','e','r','a','t','i','o','n','s',0};
1813     static const WCHAR SessionW[] = {'M','a','c','h','i','n','e','\\',
1814                                      'S','y','s','t','e','m','\\',
1815                                      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1816                                      'C','o','n','t','r','o','l','\\',
1817                                      'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
1818     static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
1819
1820     OBJECT_ATTRIBUTES attr;
1821     UNICODE_STRING nameW;
1822     KEY_VALUE_PARTIAL_INFORMATION *info;
1823     BOOL rc = FALSE;
1824     HKEY Reboot = 0;
1825     DWORD len0, len1, len2;
1826     DWORD DataSize = 0;
1827     BYTE *Buffer = NULL;
1828     WCHAR *p;
1829
1830     attr.Length = sizeof(attr);
1831     attr.RootDirectory = 0;
1832     attr.ObjectName = &nameW;
1833     attr.Attributes = 0;
1834     attr.SecurityDescriptor = NULL;
1835     attr.SecurityQualityOfService = NULL;
1836     RtlInitUnicodeString( &nameW, SessionW );
1837
1838     if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
1839     {
1840         WARN("Error creating key for reboot managment [%s]\n",
1841              "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
1842         return FALSE;
1843     }
1844
1845     len0 = strlenW(PreString);
1846     len1 = strlenW(fn1) + len0 + 1;
1847     if (fn2)
1848     {
1849         len2 = strlenW(fn2) + len0 + 1;
1850         if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
1851     }
1852     else len2 = 1; /* minimum is the 0 characters for the empty second string */
1853
1854     /* convert characters to bytes */
1855     len0 *= sizeof(WCHAR);
1856     len1 *= sizeof(WCHAR);
1857     len2 *= sizeof(WCHAR);
1858
1859     RtlInitUnicodeString( &nameW, ValueName );
1860
1861     /* First we check if the key exists and if so how many bytes it already contains. */
1862     if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1863                          NULL, 0, &DataSize ) == STATUS_BUFFER_OVERFLOW)
1864     {
1865         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1866             goto Quit;
1867         if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
1868                              Buffer, DataSize, &DataSize )) goto Quit;
1869         info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
1870         if (info->Type != REG_MULTI_SZ) goto Quit;
1871         if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR);  /* remove terminating null (will be added back later) */
1872     }
1873     else
1874     {
1875         DataSize = info_size;
1876         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
1877             goto Quit;
1878     }
1879
1880     p = (WCHAR *)(Buffer + DataSize);
1881     strcpyW( p, PreString );
1882     strcatW( p, fn1 );
1883     DataSize += len1;
1884     if (fn2)
1885     {
1886         p = (WCHAR *)(Buffer + DataSize);
1887         if (flags & MOVEFILE_REPLACE_EXISTING)
1888             *p++ = '!';
1889         strcpyW( p, PreString );
1890         strcatW( p, fn2 );
1891         DataSize += len2;
1892     }
1893     else
1894     {
1895         p = (WCHAR *)(Buffer + DataSize);
1896         *p = 0;
1897         DataSize += sizeof(WCHAR);
1898     }
1899
1900     /* add final null */
1901     p = (WCHAR *)(Buffer + DataSize);
1902     *p = 0;
1903     DataSize += sizeof(WCHAR);
1904
1905     rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
1906
1907  Quit:
1908     if (Reboot) NtClose(Reboot);
1909     if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
1910     return(rc);
1911 }
1912
1913
1914 /**************************************************************************
1915  *           MoveFileExW   (KERNEL32.@)
1916  */
1917 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
1918 {
1919     DOS_FULL_NAME full_name1, full_name2;
1920     HANDLE hFile;
1921     DWORD attr = INVALID_FILE_ATTRIBUTES;
1922
1923     TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag);
1924
1925     /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
1926        In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
1927        to be really compatible. Most programs wont have any problems though. In case
1928        you encounter one, this is what you should return here. I don't know what's up
1929        with NT 3.5. Is this function available there or not?
1930        Does anybody really care about 3.5? :)
1931     */
1932
1933     /* Filename1 has to be always set to a valid path. Filename2 may be NULL
1934        if the source file has to be deleted.
1935     */
1936     if (!fn1) {
1937         SetLastError(ERROR_INVALID_PARAMETER);
1938         return FALSE;
1939     }
1940
1941     /* This function has to be run through in order to process the name properly.
1942        If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
1943        that is the behaviour on NT 4.0. The operation accepts the filenames as
1944        they are given but it can't reply with a reasonable returncode. Success
1945        means in that case success for entering the values into the registry.
1946     */
1947     if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
1948     {
1949         if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1950             return FALSE;
1951     }
1952
1953     if (fn2)  /* !fn2 means delete fn1 */
1954     {
1955         if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
1956         {
1957             if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1958             {
1959                 /* target exists, check if we may overwrite */
1960                 if (!(flag & MOVEFILE_REPLACE_EXISTING))
1961                 {
1962                     SetLastError( ERROR_FILE_EXISTS );
1963                     return FALSE;
1964                 }
1965             }
1966         }
1967         else
1968         {
1969             if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
1970             {
1971                 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
1972                     return FALSE;
1973             }
1974         }
1975
1976         /* Source name and target path are valid */
1977
1978         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
1979         {
1980             return FILE_AddBootRenameEntry( fn1, fn2, flag );
1981         }
1982
1983         attr = GetFileAttributesW( fn1 );
1984         if ( attr == INVALID_FILE_ATTRIBUTES ) return FALSE;
1985
1986         /* check if we are allowed to rename the source */
1987         hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
1988                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
1989                                  GetDriveTypeW( full_name1.short_name ) );
1990         if (!hFile)
1991         {
1992             if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
1993             if ( !(attr & FILE_ATTRIBUTE_DIRECTORY) ) return FALSE;
1994             /* if it's a directory we can continue */
1995         }
1996         else CloseHandle(hFile);
1997
1998         /* check, if we are allowed to delete the destination,
1999         **     (but the file not being there is fine) */
2000         hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2001                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2002                                  GetDriveTypeW( full_name2.short_name ) );
2003         if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2004         CloseHandle(hFile);
2005
2006         if (full_name1.drive != full_name2.drive)
2007         {
2008             if (!(flag & MOVEFILE_COPY_ALLOWED))
2009             {
2010                 SetLastError( ERROR_NOT_SAME_DEVICE );
2011                 return FALSE;
2012             }
2013             else if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2014             {
2015                 /* Strange, but that's what Windows returns */
2016                 SetLastError ( ERROR_ACCESS_DENIED );
2017                 return FALSE;
2018             }
2019         }
2020         if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2021             /* Try copy/delete unless it's a directory. */
2022             /* FIXME: This does not handle the (unlikely) case that the two locations
2023                are on the same Wine drive, but on different Unix file systems. */
2024         {
2025             if ( attr & FILE_ATTRIBUTE_DIRECTORY )
2026             {
2027                 FILE_SetDosError();
2028                 return FALSE;
2029             }
2030             else
2031             {
2032                 if ( ! CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ))
2033                     return FALSE;
2034                 if ( ! DeleteFileW ( fn1 ) )
2035                     return FALSE;
2036             }
2037         }
2038         if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2039         {
2040             struct stat fstat;
2041             if (stat( full_name2.long_name, &fstat ) != -1)
2042             {
2043                 if (is_executable( full_name2.long_name ))
2044                     /* set executable bit where read bit is set */
2045                     fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2046                 else
2047                     fstat.st_mode &= ~0111;
2048                 chmod( full_name2.long_name, fstat.st_mode );
2049             }
2050         }
2051         return TRUE;
2052     }
2053     else /* fn2 == NULL means delete source */
2054     {
2055         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2056         {
2057             if (flag & MOVEFILE_COPY_ALLOWED) {
2058                 WARN("Illegal flag\n");
2059                 SetLastError( ERROR_GEN_FAILURE );
2060                 return FALSE;
2061             }
2062
2063             return FILE_AddBootRenameEntry( fn1, NULL, flag );
2064         }
2065
2066         if (unlink( full_name1.long_name ) == -1)
2067         {
2068             FILE_SetDosError();
2069             return FALSE;
2070         }
2071         return TRUE; /* successfully deleted */
2072     }
2073 }
2074
2075 /**************************************************************************
2076  *           MoveFileExA   (KERNEL32.@)
2077  */
2078 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2079 {
2080     UNICODE_STRING fn1W, fn2W;
2081     BOOL ret;
2082
2083     if (!fn1)
2084     {
2085         SetLastError(ERROR_INVALID_PARAMETER);
2086         return FALSE;
2087     }
2088
2089     RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1);
2090     if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2);
2091     else fn2W.Buffer = NULL;
2092
2093     ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag );
2094
2095     RtlFreeUnicodeString(&fn1W);
2096     RtlFreeUnicodeString(&fn2W);
2097     return ret;
2098 }
2099
2100
2101 /**************************************************************************
2102  *           MoveFileW   (KERNEL32.@)
2103  *
2104  *  Move file or directory
2105  */
2106 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2107 {
2108     return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2109 }
2110
2111
2112 /**************************************************************************
2113  *           MoveFileA   (KERNEL32.@)
2114  */
2115 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2116 {
2117     return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2118 }
2119
2120
2121 /**************************************************************************
2122  *           CopyFileW   (KERNEL32.@)
2123  */
2124 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
2125 {
2126     HANDLE h1, h2;
2127     BY_HANDLE_FILE_INFORMATION info;
2128     DWORD count;
2129     BOOL ret = FALSE;
2130     char buffer[2048];
2131
2132     if (!source || !dest)
2133     {
2134         SetLastError(ERROR_INVALID_PARAMETER);
2135         return FALSE;
2136     }
2137
2138     TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest));
2139
2140     if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
2141                      NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
2142     {
2143         WARN("Unable to open source %s\n", debugstr_w(source));
2144         return FALSE;
2145     }
2146
2147     if (!GetFileInformationByHandle( h1, &info ))
2148     {
2149         WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
2150         CloseHandle( h1 );
2151         return FALSE;
2152     }
2153
2154     if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2155                              fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2156                              info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2157     {
2158         WARN("Unable to open dest %s\n", debugstr_w(dest));
2159         CloseHandle( h1 );
2160         return FALSE;
2161     }
2162
2163     while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count)
2164     {
2165         char *p = buffer;
2166         while (count != 0)
2167         {
2168             DWORD res;
2169             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2170             p += res;
2171             count -= res;
2172         }
2173     }
2174     ret =  TRUE;
2175 done:
2176     CloseHandle( h1 );
2177     CloseHandle( h2 );
2178     return ret;
2179 }
2180
2181
2182 /**************************************************************************
2183  *           CopyFileA   (KERNEL32.@)
2184  */
2185 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
2186 {
2187     UNICODE_STRING sourceW, destW;
2188     BOOL ret;
2189
2190     if (!source || !dest)
2191     {
2192         SetLastError(ERROR_INVALID_PARAMETER);
2193         return FALSE;
2194     }
2195
2196     RtlCreateUnicodeStringFromAsciiz(&sourceW, source);
2197     RtlCreateUnicodeStringFromAsciiz(&destW, dest);
2198
2199     ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists);
2200
2201     RtlFreeUnicodeString(&sourceW);
2202     RtlFreeUnicodeString(&destW);
2203     return ret;
2204 }
2205
2206
2207 /**************************************************************************
2208  *           CopyFileExW   (KERNEL32.@)
2209  *
2210  * This implementation ignores most of the extra parameters passed-in into
2211  * the "ex" version of the method and calls the CopyFile method.
2212  * It will have to be fixed eventually.
2213  */
2214 BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename,
2215                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2216                         LPBOOL cancelFlagPointer, DWORD copyFlags)
2217 {
2218     /*
2219      * Interpret the only flag that CopyFile can interpret.
2220      */
2221     return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0);
2222 }
2223
2224
2225 /**************************************************************************
2226  *           CopyFileExA   (KERNEL32.@)
2227  */
2228 BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename,
2229                         LPPROGRESS_ROUTINE progressRoutine, LPVOID appData,
2230                         LPBOOL cancelFlagPointer, DWORD copyFlags)
2231 {
2232     UNICODE_STRING sourceW, destW;
2233     BOOL ret;
2234
2235     if (!sourceFilename || !destFilename)
2236     {
2237         SetLastError(ERROR_INVALID_PARAMETER);
2238         return FALSE;
2239     }
2240
2241     RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename);
2242     RtlCreateUnicodeStringFromAsciiz(&destW, destFilename);
2243
2244     ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData,
2245                       cancelFlagPointer, copyFlags);
2246
2247     RtlFreeUnicodeString(&sourceW);
2248     RtlFreeUnicodeString(&destW);
2249     return ret;
2250 }
2251
2252
2253 /***********************************************************************
2254  *              SetFileTime   (KERNEL32.@)
2255  */
2256 BOOL WINAPI SetFileTime( HANDLE hFile,
2257                            const FILETIME *lpCreationTime,
2258                            const FILETIME *lpLastAccessTime,
2259                            const FILETIME *lpLastWriteTime )
2260 {
2261     BOOL ret;
2262     SERVER_START_REQ( set_file_time )
2263     {
2264         req->handle = hFile;
2265         if (lpLastAccessTime)
2266             RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastAccessTime, (DWORD *)&req->access_time );
2267         else
2268             req->access_time = 0; /* FIXME */
2269         if (lpLastWriteTime)
2270             RtlTimeToSecondsSince1970( (PLARGE_INTEGER) lpLastWriteTime, (DWORD *)&req->write_time );
2271         else
2272             req->write_time = 0; /* FIXME */
2273         ret = !wine_server_call_err( req );
2274     }
2275     SERVER_END_REQ;
2276     return ret;
2277 }
2278
2279
2280 /**************************************************************************
2281  *           GetFileAttributesExW   (KERNEL32.@)
2282  */
2283 BOOL WINAPI GetFileAttributesExW(
2284         LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2285         LPVOID lpFileInformation)
2286 {
2287     DOS_FULL_NAME full_name;
2288     BY_HANDLE_FILE_INFORMATION info;
2289
2290     if (!lpFileName || !lpFileInformation)
2291     {
2292         SetLastError(ERROR_INVALID_PARAMETER);
2293         return FALSE;
2294     }
2295
2296     if (fInfoLevelId == GetFileExInfoStandard) {
2297         LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
2298             (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
2299         if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
2300         if (!FILE_Stat( full_name.long_name, &info, NULL )) return FALSE;
2301
2302         lpFad->dwFileAttributes = info.dwFileAttributes;
2303         lpFad->ftCreationTime   = info.ftCreationTime;
2304         lpFad->ftLastAccessTime = info.ftLastAccessTime;
2305         lpFad->ftLastWriteTime  = info.ftLastWriteTime;
2306         lpFad->nFileSizeHigh    = info.nFileSizeHigh;
2307         lpFad->nFileSizeLow     = info.nFileSizeLow;
2308     }
2309     else {
2310         FIXME("invalid info level %d!\n", fInfoLevelId);
2311         return FALSE;
2312     }
2313
2314     return TRUE;
2315 }
2316
2317
2318 /**************************************************************************
2319  *           GetFileAttributesExA   (KERNEL32.@)
2320  */
2321 BOOL WINAPI GetFileAttributesExA(
2322         LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2323         LPVOID lpFileInformation)
2324 {
2325     UNICODE_STRING filenameW;
2326     BOOL ret = FALSE;
2327
2328     if (!filename || !lpFileInformation)
2329     {
2330         SetLastError(ERROR_INVALID_PARAMETER);
2331         return FALSE;
2332     }
2333
2334     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename))
2335     {
2336         ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation);
2337         RtlFreeUnicodeString(&filenameW);
2338     }
2339     else
2340         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2341     return ret;
2342 }