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