Don't set EN_CHANGE at creation time.
[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 #include <sys/poll.h>
48 #include <time.h>
49 #ifdef HAVE_UNISTD_H
50 # include <unistd.h>
51 #endif
52 #include <utime.h>
53
54 #include "winerror.h"
55 #include "windef.h"
56 #include "winbase.h"
57 #include "wine/winbase16.h"
58 #include "wine/server.h"
59
60 #include "drive.h"
61 #include "file.h"
62 #include "async.h"
63 #include "heap.h"
64 #include "msdos.h"
65 #include "wincon.h"
66
67 #include "smb.h"
68 #include "wine/debug.h"
69
70 WINE_DEFAULT_DEBUG_CHANNEL(file);
71
72 #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
73 #define MAP_ANON MAP_ANONYMOUS
74 #endif
75
76 /* Size of per-process table of DOS handles */
77 #define DOS_TABLE_SIZE 256
78
79 /* Macro to derive file offset from OVERLAPPED struct */
80 #define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32))
81
82 static HANDLE dos_handles[DOS_TABLE_SIZE];
83
84 mode_t FILE_umask;
85
86 extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name);
87
88 /***********************************************************************
89  *                  Asynchronous file I/O                              *
90  */
91 static DWORD fileio_get_async_status (const async_private *ovp);
92 static DWORD fileio_get_async_count (const async_private *ovp);
93 static void fileio_set_async_status (async_private *ovp, const DWORD status);
94 static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
95 static void fileio_async_cleanup (async_private *ovp);
96
97 static async_ops fileio_async_ops =
98 {
99     fileio_get_async_status,       /* get_status */
100     fileio_set_async_status,       /* set_status */
101     fileio_get_async_count,        /* get_count */
102     fileio_call_completion_func,   /* call_completion */
103     fileio_async_cleanup           /* cleanup */
104 };
105
106 static async_ops fileio_nocomp_async_ops =
107 {
108     fileio_get_async_status,       /* get_status */
109     fileio_set_async_status,       /* set_status */
110     fileio_get_async_count,        /* get_count */
111     NULL,                          /* call_completion */
112     fileio_async_cleanup           /* cleanup */
113 };
114
115 typedef struct async_fileio
116 {
117     struct async_private             async;
118     LPOVERLAPPED                     lpOverlapped;
119     LPOVERLAPPED_COMPLETION_ROUTINE  completion_func;
120     char                             *buffer;
121     int                              count;
122     enum fd_type                     fd_type;
123 } async_fileio;
124
125 static DWORD fileio_get_async_status (const struct async_private *ovp)
126 {
127     return ((async_fileio*) ovp)->lpOverlapped->Internal;
128 }
129
130 static void fileio_set_async_status (async_private *ovp, const DWORD status)
131 {
132     ((async_fileio*) ovp)->lpOverlapped->Internal = status;
133 }
134
135 static DWORD fileio_get_async_count (const struct async_private *ovp)
136 {
137     async_fileio *fileio = (async_fileio*) ovp;
138     DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
139     return (ret < 0 ? 0 : ret);
140 }
141
142 static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
143 {
144     async_fileio *ovp = (async_fileio*) data;
145     TRACE ("data: %p\n", ovp);
146
147     ovp->completion_func( ovp->lpOverlapped->Internal,
148                           ovp->lpOverlapped->InternalHigh,
149                           ovp->lpOverlapped );
150
151     fileio_async_cleanup ( &ovp->async );
152 }
153
154 static void fileio_async_cleanup ( struct async_private *ovp )
155 {
156     HeapFree ( GetProcessHeap(), 0, ovp );
157 }
158
159 /***********************************************************************
160  *              FILE_ConvertOFMode
161  *
162  * Convert OF_* mode into flags for CreateFile.
163  */
164 static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing )
165 {
166     switch(mode & 0x03)
167     {
168     case OF_READ:      *access = GENERIC_READ; break;
169     case OF_WRITE:     *access = GENERIC_WRITE; break;
170     case OF_READWRITE: *access = GENERIC_READ | GENERIC_WRITE; break;
171     default:           *access = 0; break;
172     }
173     switch(mode & 0x70)
174     {
175     case OF_SHARE_EXCLUSIVE:  *sharing = 0; break;
176     case OF_SHARE_DENY_WRITE: *sharing = FILE_SHARE_READ; break;
177     case OF_SHARE_DENY_READ:  *sharing = FILE_SHARE_WRITE; break;
178     case OF_SHARE_DENY_NONE:
179     case OF_SHARE_COMPAT:
180     default:                  *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
181     }
182 }
183
184
185 /***********************************************************************
186  *              FILE_strcasecmp
187  *
188  * locale-independent case conversion for file I/O
189  */
190 int FILE_strcasecmp( const char *str1, const char *str2 )
191 {
192     for (;;)
193     {
194         int ret = FILE_toupper(*str1) - FILE_toupper(*str2);
195         if (ret || !*str1) return ret;
196         str1++;
197         str2++;
198     }
199 }
200
201
202 /***********************************************************************
203  *              FILE_strncasecmp
204  *
205  * locale-independent case conversion for file I/O
206  */
207 int FILE_strncasecmp( const char *str1, const char *str2, int len )
208 {
209     int ret = 0;
210     for ( ; len > 0; len--, str1++, str2++)
211         if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break;
212     return ret;
213 }
214
215
216 /***********************************************************************
217  *           FILE_GetNtStatus(void)
218  *
219  * Retrieve the Nt Status code from errno.
220  * Try to be consistent with FILE_SetDosError().
221  */
222 DWORD FILE_GetNtStatus(void)
223 {
224     int err = errno;
225     DWORD nt;
226     TRACE ( "errno = %d\n", errno );
227     switch ( err )
228     {
229     case EAGAIN:       nt = STATUS_SHARING_VIOLATION;       break;
230     case EBADF:        nt = STATUS_INVALID_HANDLE;          break;
231     case ENOSPC:       nt = STATUS_DISK_FULL;               break;
232     case EPERM:
233     case EROFS:
234     case EACCES:       nt = STATUS_ACCESS_DENIED;           break;
235     case ENOENT:       nt = STATUS_SHARING_VIOLATION;       break;
236     case EISDIR:       nt = STATUS_FILE_IS_A_DIRECTORY;     break;
237     case EMFILE:
238     case ENFILE:       nt = STATUS_NO_MORE_FILES;           break;
239     case EINVAL:
240     case ENOTEMPTY:    nt = STATUS_DIRECTORY_NOT_EMPTY;     break;
241     case EPIPE:        nt = STATUS_PIPE_BROKEN;             break;
242     case ENOEXEC:      /* ?? */
243     case ESPIPE:       /* ?? */
244     case EEXIST:       /* ?? */
245     default:
246         FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err );
247         nt = STATUS_UNSUCCESSFUL;
248     }
249     return nt;
250 }
251
252 /***********************************************************************
253  *           FILE_SetDosError
254  *
255  * Set the DOS error code from errno.
256  */
257 void FILE_SetDosError(void)
258 {
259     int save_errno = errno; /* errno gets overwritten by printf */
260
261     TRACE("errno = %d %s\n", errno, strerror(errno));
262     switch (save_errno)
263     {
264     case EAGAIN:
265         SetLastError( ERROR_SHARING_VIOLATION );
266         break;
267     case EBADF:
268         SetLastError( ERROR_INVALID_HANDLE );
269         break;
270     case ENOSPC:
271         SetLastError( ERROR_HANDLE_DISK_FULL );
272         break;
273     case EACCES:
274     case EPERM:
275     case EROFS:
276         SetLastError( ERROR_ACCESS_DENIED );
277         break;
278     case EBUSY:
279         SetLastError( ERROR_LOCK_VIOLATION );
280         break;
281     case ENOENT:
282         SetLastError( ERROR_FILE_NOT_FOUND );
283         break;
284     case EISDIR:
285         SetLastError( ERROR_CANNOT_MAKE );
286         break;
287     case ENFILE:
288     case EMFILE:
289         SetLastError( ERROR_NO_MORE_FILES );
290         break;
291     case EEXIST:
292         SetLastError( ERROR_FILE_EXISTS );
293         break;
294     case EINVAL:
295     case ESPIPE:
296         SetLastError( ERROR_SEEK );
297         break;
298     case ENOTEMPTY:
299         SetLastError( ERROR_DIR_NOT_EMPTY );
300         break;
301     case ENOEXEC:
302         SetLastError( ERROR_BAD_FORMAT );
303         break;
304     default:
305         WARN("unknown file error: %s\n", strerror(save_errno) );
306         SetLastError( ERROR_GEN_FAILURE );
307         break;
308     }
309     errno = save_errno;
310 }
311
312
313 /***********************************************************************
314  *           FILE_GetUnixHandleType
315  *
316  * Retrieve the Unix handle corresponding to a file handle.
317  * Returns -1 on failure.
318  */
319 static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr )
320 {
321     int ret, flags, fd = -1;
322
323     ret = wine_server_handle_to_fd( handle, access, &fd, type, &flags );
324     if (flags_ptr) *flags_ptr = flags;
325     if (ret) SetLastError( RtlNtStatusToDosError(ret) );
326     else if (((access & GENERIC_READ)  && (flags & FD_FLAG_RECV_SHUTDOWN)) ||
327              ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))
328     {
329         close (fd);
330         SetLastError ( ERROR_PIPE_NOT_CONNECTED );
331         return -1;
332     }
333     return fd;
334 }
335
336 /***********************************************************************
337  *           FILE_GetUnixHandle
338  *
339  * Retrieve the Unix handle corresponding to a file handle.
340  * Returns -1 on failure.
341  */
342 int FILE_GetUnixHandle( HANDLE handle, DWORD access )
343 {
344     return FILE_GetUnixHandleType( handle, access, NULL, NULL );
345 }
346
347 /*************************************************************************
348  *              FILE_OpenConsole
349  *
350  * Open a handle to the current process console.
351  * Returns 0 on failure.
352  */
353 static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
354 {
355     HANDLE ret;
356
357     SERVER_START_REQ( open_console )
358     {
359         req->from    = output;
360         req->access  = access;
361         req->share   = sharing;
362         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
363         SetLastError(0);
364         wine_server_call_err( req );
365         ret = reply->handle;
366     }
367     SERVER_END_REQ;
368     return ret;
369 }
370
371 /* FIXME: those routines defined as pointers are needed, because this file is
372  * currently compiled into NTDLL whereas it belongs to kernel32.
373  * this shall go away once all the DLL separation process is done
374  */
375 typedef BOOL    (WINAPI* pRW)(HANDLE, const void*, DWORD, DWORD*, void*);
376
377 static  BOOL FILE_ReadConsole(HANDLE hCon, void* buf, DWORD nb, DWORD* nr, void* p)
378 {
379     static      HANDLE  hKernel /* = 0 */;
380     static      pRW     pReadConsole  /* = 0 */;
381
382     if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
383         (!pReadConsole &&
384          !(pReadConsole = GetProcAddress(hKernel, "ReadConsoleA"))))
385     {
386         *nr = 0;
387         return 0;
388     }
389     return (pReadConsole)(hCon, buf, nb, nr, p);
390 }
391
392 static  BOOL FILE_WriteConsole(HANDLE hCon, const void* buf, DWORD nb, DWORD* nr, void* p)
393 {
394     static      HANDLE  hKernel /* = 0 */;
395     static      pRW     pWriteConsole  /* = 0 */;
396
397     if ((!hKernel && !(hKernel = LoadLibraryA("kernel32"))) ||
398         (!pWriteConsole &&
399          !(pWriteConsole = GetProcAddress(hKernel, "WriteConsoleA"))))
400     {
401         *nr = 0;
402         return 0;
403     }
404     return (pWriteConsole)(hCon, buf, nb, nr, p);
405 }
406 /* end of FIXME */
407
408 /***********************************************************************
409  *           FILE_CreateFile
410  *
411  * Implementation of CreateFile. Takes a Unix path name.
412  * Returns 0 on failure.
413  */
414 HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
415                         LPSECURITY_ATTRIBUTES sa, DWORD creation,
416                         DWORD attributes, HANDLE template, BOOL fail_read_only,
417                         UINT drive_type )
418 {
419     unsigned int err;
420     HANDLE ret;
421
422     for (;;)
423     {
424         SERVER_START_REQ( create_file )
425         {
426             req->access     = access;
427             req->inherit    = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
428             req->sharing    = sharing;
429             req->create     = creation;
430             req->attrs      = attributes;
431             req->drive_type = drive_type;
432             wine_server_add_data( req, filename, strlen(filename) );
433             SetLastError(0);
434             err = wine_server_call( req );
435             ret = reply->handle;
436         }
437         SERVER_END_REQ;
438
439         /* If write access failed, retry without GENERIC_WRITE */
440
441         if (!ret && !fail_read_only && (access & GENERIC_WRITE))
442         {
443             if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
444             {
445                 TRACE("Write access failed for file '%s', trying without "
446                       "write access\n", filename);
447                 access &= ~GENERIC_WRITE;
448                 continue;
449             }
450         }
451
452         if (err) SetLastError( RtlNtStatusToDosError(err) );
453
454         if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
455         return ret;
456     }
457 }
458
459
460 /***********************************************************************
461  *           FILE_CreateDevice
462  *
463  * Same as FILE_CreateFile but for a device
464  * Returns 0 on failure.
465  */
466 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
467 {
468     HANDLE ret;
469     SERVER_START_REQ( create_device )
470     {
471         req->access  = access;
472         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
473         req->id      = client_id;
474         SetLastError(0);
475         wine_server_call_err( req );
476         ret = reply->handle;
477     }
478     SERVER_END_REQ;
479     return ret;
480 }
481
482 static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access)
483 {
484     WCHAR buffer[MAX_PATH];
485     HANDLE ret;
486     DWORD len = 0;
487
488     if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH )))
489     {
490         SetLastError( ERROR_FILENAME_EXCED_RANGE );
491         return 0;
492     }
493     SERVER_START_REQ( open_named_pipe )
494     {
495         req->access = access;
496         SetLastError(0);
497         wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
498         wine_server_call_err( req );
499         ret = reply->handle;
500     }
501     SERVER_END_REQ;
502     TRACE("Returned %d\n",ret);
503     return ret;
504 }
505
506 /*************************************************************************
507  * CreateFileA [KERNEL32.@]  Creates or opens a file or other object
508  *
509  * Creates or opens an object, and returns a handle that can be used to
510  * access that object.
511  *
512  * PARAMS
513  *
514  * filename     [in] pointer to filename to be accessed
515  * access       [in] access mode requested
516  * sharing      [in] share mode
517  * sa           [in] pointer to security attributes
518  * creation     [in] how to create the file
519  * attributes   [in] attributes for newly created file
520  * template     [in] handle to file with extended attributes to copy
521  *
522  * RETURNS
523  *   Success: Open handle to specified file
524  *   Failure: INVALID_HANDLE_VALUE
525  *
526  * NOTES
527  *  Should call SetLastError() on failure.
528  *
529  * BUGS
530  *
531  * Doesn't support character devices, template files, or a
532  * lot of the 'attributes' flags yet.
533  */
534 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
535                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
536                               DWORD attributes, HANDLE template )
537 {
538     DOS_FULL_NAME full_name;
539     HANDLE ret;
540
541     if (!filename)
542     {
543         SetLastError( ERROR_INVALID_PARAMETER );
544         return INVALID_HANDLE_VALUE;
545     }
546     TRACE("%s %s%s%s%s%s%s%s\n",filename,
547           ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"",
548           ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"",
549           (!access)?"QUERY_ACCESS ":"",
550           ((sharing & FILE_SHARE_READ)==FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
551           ((sharing & FILE_SHARE_WRITE)==FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
552           ((sharing & FILE_SHARE_DELETE)==FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
553           (creation ==CREATE_NEW)?"CREATE_NEW":
554           (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ":
555           (creation ==OPEN_EXISTING)?"OPEN_EXISTING ":
556           (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ":
557           (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"");
558
559     /* If the name starts with '\\?\', ignore the first 4 chars. */
560     if (!strncmp(filename, "\\\\?\\", 4))
561     {
562         filename += 4;
563         if (!strncmp(filename, "UNC\\", 4))
564         {
565             FIXME("UNC name (%s) not supported.\n", filename );
566             SetLastError( ERROR_PATH_NOT_FOUND );
567             return INVALID_HANDLE_VALUE;
568         }
569     }
570
571     if (!strncmp(filename, "\\\\.\\", 4)) {
572         if(!strncasecmp(&filename[4],"pipe\\",5))
573         {
574             TRACE("Opening a pipe: %s\n",filename);
575             ret = FILE_OpenPipe(filename,access);
576             goto done;
577         }
578         else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
579         {
580             ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
581             goto done;
582         }
583         else if (!DOSFS_GetDevice( filename ))
584         {
585             ret = DEVICE_Open( filename+4, access, sa );
586             goto done;
587         }
588         else
589                 filename+=4; /* fall into DOSFS_Device case below */
590     }
591
592     /* If the name still starts with '\\', it's a UNC name. */
593     if (!strncmp(filename, "\\\\", 2))
594     {
595         ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template );
596         goto done;
597     }
598
599     /* If the name contains a DOS wild card (* or ?), do no create a file */
600     if(strchr(filename,'*') || strchr(filename,'?'))
601         return INVALID_HANDLE_VALUE;
602
603     /* Open a console for CONIN$ or CONOUT$ */
604     if (!strcasecmp(filename, "CONIN$"))
605     {
606         ret = FILE_OpenConsole( FALSE, access, sharing, sa );
607         goto done;
608     }
609     if (!strcasecmp(filename, "CONOUT$"))
610     {
611         ret = FILE_OpenConsole( TRUE, access, sharing, sa );
612         goto done;
613     }
614
615     if (DOSFS_GetDevice( filename ))
616     {
617         TRACE("opening device '%s'\n", 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",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              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                            GetDriveTypeA( full_name.short_name ) );
642  done:
643     if (!ret) ret = INVALID_HANDLE_VALUE;
644     return ret;
645 }
646
647
648
649 /*************************************************************************
650  *              CreateFileW              (KERNEL32.@)
651  */
652 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
653                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
654                               DWORD attributes, HANDLE template)
655 {
656     LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
657     HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template );
658     HeapFree( GetProcessHeap(), 0, afn );
659     return res;
660 }
661
662
663 /***********************************************************************
664  *           FILE_FillInfo
665  *
666  * Fill a file information from a struct stat.
667  */
668 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
669 {
670     if (S_ISDIR(st->st_mode))
671         info->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
672     else
673         info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
674     if (!(st->st_mode & S_IWUSR))
675         info->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
676
677     RtlSecondsSince1970ToTime( st->st_mtime, &info->ftCreationTime );
678     RtlSecondsSince1970ToTime( st->st_mtime, &info->ftLastWriteTime );
679     RtlSecondsSince1970ToTime( st->st_atime, &info->ftLastAccessTime );
680
681     info->dwVolumeSerialNumber = 0;  /* FIXME */
682     info->nFileSizeHigh = 0;
683     info->nFileSizeLow  = 0;
684     if (!S_ISDIR(st->st_mode)) {
685         info->nFileSizeHigh = st->st_size >> 32;
686         info->nFileSizeLow  = st->st_size & 0xffffffff;
687     }
688     info->nNumberOfLinks = st->st_nlink;
689     info->nFileIndexHigh = 0;
690     info->nFileIndexLow  = st->st_ino;
691 }
692
693
694 /***********************************************************************
695  *           FILE_Stat
696  *
697  * Stat a Unix path name. Return TRUE if OK.
698  */
699 BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
700 {
701     struct stat st;
702
703     if (lstat( unixName, &st ) == -1)
704     {
705         FILE_SetDosError();
706         return FALSE;
707     }
708     if (!S_ISLNK(st.st_mode)) FILE_FillInfo( &st, info );
709     else
710     {
711         /* do a "real" stat to find out
712            about the type of the symlink destination */
713         if (stat( unixName, &st ) == -1)
714         {
715             FILE_SetDosError();
716             return FALSE;
717         }
718         FILE_FillInfo( &st, info );
719         info->dwFileAttributes |= FILE_ATTRIBUTE_SYMLINK;
720     }
721     return TRUE;
722 }
723
724
725 /***********************************************************************
726  *             GetFileInformationByHandle   (KERNEL32.@)
727  */
728 DWORD WINAPI GetFileInformationByHandle( HANDLE hFile,
729                                          BY_HANDLE_FILE_INFORMATION *info )
730 {
731     DWORD ret;
732     if (!info) return 0;
733
734     SERVER_START_REQ( get_file_info )
735     {
736         req->handle = hFile;
737         if ((ret = !wine_server_call_err( req )))
738         {
739             /* FIXME: which file types are supported ?
740              * Serial ports (FILE_TYPE_CHAR) are not,
741              * and MSDN also says that pipes are not supported.
742              * FILE_TYPE_REMOTE seems to be supported according to
743              * MSDN q234741.txt */
744             if ((reply->type == FILE_TYPE_DISK) ||  (reply->type == FILE_TYPE_REMOTE))
745             {
746                 RtlSecondsSince1970ToTime( reply->write_time, &info->ftCreationTime );
747                 RtlSecondsSince1970ToTime( reply->write_time, &info->ftLastWriteTime );
748                 RtlSecondsSince1970ToTime( reply->access_time, &info->ftLastAccessTime );
749                 info->dwFileAttributes     = reply->attr;
750                 info->dwVolumeSerialNumber = reply->serial;
751                 info->nFileSizeHigh        = reply->size_high;
752                 info->nFileSizeLow         = reply->size_low;
753                 info->nNumberOfLinks       = reply->links;
754                 info->nFileIndexHigh       = reply->index_high;
755                 info->nFileIndexLow        = reply->index_low;
756             }
757             else
758             {
759                 SetLastError(ERROR_NOT_SUPPORTED);
760                 ret = 0;
761             }
762         }
763     }
764     SERVER_END_REQ;
765     return ret;
766 }
767
768
769 /**************************************************************************
770  *           GetFileAttributes   (KERNEL.420)
771  */
772 DWORD WINAPI GetFileAttributes16( LPCSTR name )
773 {
774     return GetFileAttributesA( name );
775 }
776
777
778 /**************************************************************************
779  *           GetFileAttributesA   (KERNEL32.@)
780  */
781 DWORD WINAPI GetFileAttributesA( LPCSTR name )
782 {
783     DOS_FULL_NAME full_name;
784     BY_HANDLE_FILE_INFORMATION info;
785
786     if (name == NULL)
787     {
788         SetLastError( ERROR_INVALID_PARAMETER );
789         return -1;
790     }
791     if (!DOSFS_GetFullName( name, TRUE, &full_name) )
792         return -1;
793     if (!FILE_Stat( full_name.long_name, &info )) return -1;
794     return info.dwFileAttributes;
795 }
796
797
798 /**************************************************************************
799  *           GetFileAttributesW   (KERNEL32.@)
800  */
801 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
802 {
803     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
804     DWORD res = GetFileAttributesA( nameA );
805     HeapFree( GetProcessHeap(), 0, nameA );
806     return res;
807 }
808
809
810 /**************************************************************************
811  *              SetFileAttributes       (KERNEL.421)
812  */
813 BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes )
814 {
815     return SetFileAttributesA( lpFileName, attributes );
816 }
817
818
819 /**************************************************************************
820  *              SetFileAttributesA      (KERNEL32.@)
821  */
822 BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes)
823 {
824     struct stat buf;
825     DOS_FULL_NAME full_name;
826
827     if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name ))
828         return FALSE;
829
830     TRACE("(%s,%lx)\n",lpFileName,attributes);
831     if(stat(full_name.long_name,&buf)==-1)
832     {
833         FILE_SetDosError();
834         return FALSE;
835     }
836     if (attributes & FILE_ATTRIBUTE_READONLY)
837     {
838         if(S_ISDIR(buf.st_mode))
839             /* FIXME */
840             WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n");
841         else
842             buf.st_mode &= ~0222; /* octal!, clear write permission bits */
843         attributes &= ~FILE_ATTRIBUTE_READONLY;
844     }
845     else
846     {
847         /* add write permission */
848         buf.st_mode |= (0600 | ((buf.st_mode & 044) >> 1)) & (~FILE_umask);
849     }
850     if (attributes & FILE_ATTRIBUTE_DIRECTORY)
851     {
852         if (!S_ISDIR(buf.st_mode))
853             FIXME("SetFileAttributes expected the file '%s' to be a directory\n",
854                   lpFileName);
855         attributes &= ~FILE_ATTRIBUTE_DIRECTORY;
856     }
857     attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
858     if (attributes)
859         FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes);
860     if (-1==chmod(full_name.long_name,buf.st_mode))
861     {
862         if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) {
863            SetLastError( ERROR_ACCESS_DENIED );
864            return FALSE;
865         }
866
867         /*
868         * FIXME: We don't return FALSE here because of differences between
869         *        Linux and Windows privileges. Under Linux only the owner of
870         *        the file is allowed to change file attributes. Under Windows,
871         *        applications expect that if you can write to a file, you can also
872         *        change its attributes (see GENERIC_WRITE). We could try to be
873         *        clever here but that would break multi-user installations where
874         *        users share read-only DLLs. This is because some installers like
875         *        to change attributes of already installed DLLs.
876         */
877         FIXME("Couldn't set file attributes for existing file \"%s\".\n"
878               "Check permissions or set VFAT \"quiet\" mount flag\n", full_name.long_name);
879     }
880     return TRUE;
881 }
882
883
884 /**************************************************************************
885  *              SetFileAttributesW      (KERNEL32.@)
886  */
887 BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes)
888 {
889     BOOL res;
890     DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL );
891     LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len );
892
893     WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL );
894     res = SetFileAttributesA( afn, attributes );
895     HeapFree( GetProcessHeap(), 0, afn );
896     return res;
897 }
898
899
900 /***********************************************************************
901  *           GetFileSize   (KERNEL32.@)
902  */
903 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
904 {
905     BY_HANDLE_FILE_INFORMATION info;
906     if (!GetFileInformationByHandle( hFile, &info )) return -1;
907     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
908     return info.nFileSizeLow;
909 }
910
911
912 /***********************************************************************
913  *           GetFileTime   (KERNEL32.@)
914  */
915 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
916                            FILETIME *lpLastAccessTime,
917                            FILETIME *lpLastWriteTime )
918 {
919     BY_HANDLE_FILE_INFORMATION info;
920     if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
921     if (lpCreationTime)   *lpCreationTime   = info.ftCreationTime;
922     if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
923     if (lpLastWriteTime)  *lpLastWriteTime  = info.ftLastWriteTime;
924     return TRUE;
925 }
926
927 /***********************************************************************
928  *           CompareFileTime   (KERNEL32.@)
929  */
930 INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y )
931 {
932         if (!x || !y) return -1;
933
934         if (x->dwHighDateTime > y->dwHighDateTime)
935                 return 1;
936         if (x->dwHighDateTime < y->dwHighDateTime)
937                 return -1;
938         if (x->dwLowDateTime > y->dwLowDateTime)
939                 return 1;
940         if (x->dwLowDateTime < y->dwLowDateTime)
941                 return -1;
942         return 0;
943 }
944
945 /***********************************************************************
946  *           FILE_GetTempFileName : utility for GetTempFileName
947  */
948 static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique,
949                                   LPSTR buffer, BOOL isWin16 )
950 {
951     static UINT unique_temp;
952     DOS_FULL_NAME full_name;
953     int i;
954     LPSTR p;
955     UINT num;
956
957     if ( !path || !prefix || !buffer ) return 0;
958
959     if (!unique_temp) unique_temp = time(NULL) & 0xffff;
960     num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff);
961
962     strcpy( buffer, path );
963     p = buffer + strlen(buffer);
964
965     /* add a \, if there isn't one and path is more than just the drive letter ... */
966     if ( !((strlen(buffer) == 2) && (buffer[1] == ':'))
967         && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\';
968
969     if (isWin16) *p++ = '~';
970     for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
971     sprintf( p, "%04x.tmp", num );
972
973     /* Now try to create it */
974
975     if (!unique)
976     {
977         do
978         {
979             HANDLE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
980                                          CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
981             if (handle != INVALID_HANDLE_VALUE)
982             {  /* We created it */
983                 TRACE("created %s\n",
984                               buffer);
985                 CloseHandle( handle );
986                 break;
987             }
988             if (GetLastError() != ERROR_FILE_EXISTS)
989                 break;  /* No need to go on */
990             num++;
991             sprintf( p, "%04x.tmp", num );
992         } while (num != (unique & 0xffff));
993     }
994
995     /* Get the full path name */
996
997     if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
998     {
999         /* Check if we have write access in the directory */
1000         if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0';
1001         if (access( full_name.long_name, W_OK ) == -1)
1002             WARN("returns '%s', which doesn't seem to be writeable.\n",
1003                  buffer);
1004     }
1005     TRACE("returning %s\n", buffer );
1006     return unique ? unique : num;
1007 }
1008
1009
1010 /***********************************************************************
1011  *           GetTempFileNameA   (KERNEL32.@)
1012  */
1013 UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique,
1014                                   LPSTR buffer)
1015 {
1016     return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE);
1017 }
1018
1019 /***********************************************************************
1020  *           GetTempFileNameW   (KERNEL32.@)
1021  */
1022 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique,
1023                                   LPWSTR buffer )
1024 {
1025     LPSTR   patha,prefixa;
1026     char    buffera[144];
1027     UINT  ret;
1028
1029     if (!path) return 0;
1030     patha   = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1031     prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
1032     ret     = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE );
1033     MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH );
1034     HeapFree( GetProcessHeap(), 0, patha );
1035     HeapFree( GetProcessHeap(), 0, prefixa );
1036     return ret;
1037 }
1038
1039
1040 /***********************************************************************
1041  *           GetTempFileName   (KERNEL.97)
1042  */
1043 UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
1044                                  LPSTR buffer )
1045 {
1046     char temppath[144];
1047
1048     if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */
1049         drive |= DRIVE_GetCurrentDrive() + 'A';
1050
1051     if ((drive & TF_FORCEDRIVE) &&
1052         !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
1053     {
1054         drive &= ~TF_FORCEDRIVE;
1055         WARN("invalid drive %d specified\n", drive );
1056     }
1057
1058     if (drive & TF_FORCEDRIVE)
1059         sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
1060     else
1061         GetTempPathA( 132, temppath );
1062     return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE );
1063 }
1064
1065 /***********************************************************************
1066  *           FILE_DoOpenFile
1067  *
1068  * Implementation of OpenFile16() and OpenFile32().
1069  */
1070 static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode,
1071                                 BOOL win32 )
1072 {
1073     HFILE hFileRet;
1074     HANDLE handle;
1075     FILETIME filetime;
1076     WORD filedatetime[2];
1077     DOS_FULL_NAME full_name;
1078     DWORD access, sharing;
1079     char *p;
1080
1081     if (!ofs) return HFILE_ERROR;
1082
1083     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1084           ((mode & 0x3 )==OF_READ)?"OF_READ":
1085           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1086           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1087           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1088           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1089           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1090           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1091           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1092           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1093           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1094           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1095           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1096           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1097           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1098           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1099           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1100           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1101           );
1102
1103
1104     ofs->cBytes = sizeof(OFSTRUCT);
1105     ofs->nErrCode = 0;
1106     if (mode & OF_REOPEN) name = ofs->szPathName;
1107
1108     if (!name) {
1109         ERR("called with `name' set to NULL ! Please debug.\n");
1110         return HFILE_ERROR;
1111     }
1112
1113     TRACE("%s %04x\n", name, mode );
1114
1115     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1116        Are there any cases where getting the path here is wrong?
1117        Uwe Bonnes 1997 Apr 2 */
1118     if (!GetFullPathNameA( name, sizeof(ofs->szPathName),
1119                              ofs->szPathName, NULL )) goto error;
1120     FILE_ConvertOFMode( mode, &access, &sharing );
1121
1122     /* OF_PARSE simply fills the structure */
1123
1124     if (mode & OF_PARSE)
1125     {
1126         ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
1127                            != DRIVE_REMOVABLE);
1128         TRACE("(%s): OF_PARSE, res = '%s'\n",
1129                       name, ofs->szPathName );
1130         return 0;
1131     }
1132
1133     /* OF_CREATE is completely different from all other options, so
1134        handle it first */
1135
1136     if (mode & OF_CREATE)
1137     {
1138         if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1139                                    sharing, NULL, CREATE_ALWAYS,
1140                                    FILE_ATTRIBUTE_NORMAL, 0 ))== INVALID_HANDLE_VALUE)
1141             goto error;
1142         goto success;
1143     }
1144
1145     /* If OF_SEARCH is set, ignore the given path */
1146
1147     if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
1148     {
1149         /* First try the file name as is */
1150         if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
1151         /* Now remove the path */
1152         if (name[0] && (name[1] == ':')) name += 2;
1153         if ((p = strrchr( name, '\\' ))) name = p + 1;
1154         if ((p = strrchr( name, '/' ))) name = p + 1;
1155         if (!name[0]) goto not_found;
1156     }
1157
1158     /* Now look for the file */
1159
1160     if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
1161
1162 found:
1163     TRACE("found %s = %s\n",
1164                   full_name.long_name, full_name.short_name );
1165     lstrcpynA( ofs->szPathName, full_name.short_name,
1166                  sizeof(ofs->szPathName) );
1167
1168     if (mode & OF_SHARE_EXCLUSIVE)
1169       /* Some InstallShield version uses OF_SHARE_EXCLUSIVE
1170          on the file <tempdir>/_ins0432._mp to determine how
1171          far installation has proceeded.
1172          _ins0432._mp is an executable and while running the
1173          application expects the open with OF_SHARE_ to fail*/
1174       /* Probable FIXME:
1175          As our loader closes the files after loading the executable,
1176          we can't find the running executable with FILE_InUse.
1177          The loader should keep the file open, as Windows does that, too.
1178        */
1179       {
1180         char *last = strrchr(full_name.long_name,'/');
1181         if (!last)
1182           last = full_name.long_name - 1;
1183         if (GetModuleHandle16(last+1))
1184           {
1185             TRACE("Denying shared open for %s\n",full_name.long_name);
1186             return HFILE_ERROR;
1187           }
1188       }
1189
1190     if (mode & OF_DELETE)
1191     {
1192         if (unlink( full_name.long_name ) == -1) goto not_found;
1193         TRACE("(%s): OF_DELETE return = OK\n", name);
1194         return 1;
1195     }
1196
1197     handle = FILE_CreateFile( full_name.long_name, access, sharing,
1198                               NULL, OPEN_EXISTING, 0, 0,
1199                               DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY,
1200                               GetDriveTypeA( full_name.short_name ) );
1201     if (!handle) goto not_found;
1202
1203     GetFileTime( handle, NULL, NULL, &filetime );
1204     FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1205     if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1206     {
1207         if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
1208         {
1209             CloseHandle( handle );
1210             WARN("(%s): OF_VERIFY failed\n", name );
1211             /* FIXME: what error here? */
1212             SetLastError( ERROR_FILE_NOT_FOUND );
1213             goto error;
1214         }
1215     }
1216     memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
1217
1218 success:  /* We get here if the open was successful */
1219     TRACE("(%s): OK, return = %x\n", name, handle );
1220     if (win32)
1221     {
1222         hFileRet = (HFILE)handle;
1223         if (mode & OF_EXIST) /* Return the handle, but close it first */
1224             CloseHandle( handle );
1225     }
1226     else
1227     {
1228         hFileRet = Win32HandleToDosFileHandle( handle );
1229         if (hFileRet == HFILE_ERROR16) goto error;
1230         if (mode & OF_EXIST) /* Return the handle, but close it first */
1231             _lclose16( hFileRet );
1232     }
1233     return hFileRet;
1234
1235 not_found:  /* We get here if the file does not exist */
1236     WARN("'%s' not found or sharing violation\n", name );
1237     SetLastError( ERROR_FILE_NOT_FOUND );
1238     /* fall through */
1239
1240 error:  /* We get here if there was an error opening the file */
1241     ofs->nErrCode = GetLastError();
1242     WARN("(%s): return = HFILE_ERROR error= %d\n",
1243                   name,ofs->nErrCode );
1244     return HFILE_ERROR;
1245 }
1246
1247
1248 /***********************************************************************
1249  *           OpenFile   (KERNEL.74)
1250  *           OpenFileEx (KERNEL.360)
1251  */
1252 HFILE16 WINAPI OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
1253 {
1254     return FILE_DoOpenFile( name, ofs, mode, FALSE );
1255 }
1256
1257
1258 /***********************************************************************
1259  *           OpenFile   (KERNEL32.@)
1260  */
1261 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1262 {
1263     return FILE_DoOpenFile( name, ofs, mode, TRUE );
1264 }
1265
1266
1267 /***********************************************************************
1268  *           FILE_InitProcessDosHandles
1269  *
1270  * Allocates the default DOS handles for a process. Called either by
1271  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
1272  */
1273 static void FILE_InitProcessDosHandles( void )
1274 {
1275     HANDLE cp = GetCurrentProcess();
1276     DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
1277                     0, TRUE, DUPLICATE_SAME_ACCESS);
1278     DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
1279                     0, TRUE, DUPLICATE_SAME_ACCESS);
1280     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
1281                     0, TRUE, DUPLICATE_SAME_ACCESS);
1282     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
1283                     0, TRUE, DUPLICATE_SAME_ACCESS);
1284     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
1285                     0, TRUE, DUPLICATE_SAME_ACCESS);
1286 }
1287
1288 /***********************************************************************
1289  *           Win32HandleToDosFileHandle   (KERNEL32.21)
1290  *
1291  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1292  * longer valid after this function (even on failure).
1293  *
1294  * Note: this is not exactly right, since on Win95 the Win32 handles
1295  *       are on top of DOS handles and we do it the other way
1296  *       around. Should be good enough though.
1297  */
1298 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1299 {
1300     int i;
1301
1302     if (!handle || (handle == INVALID_HANDLE_VALUE))
1303         return HFILE_ERROR;
1304
1305     for (i = 5; i < DOS_TABLE_SIZE; i++)
1306         if (!dos_handles[i])
1307         {
1308             dos_handles[i] = handle;
1309             TRACE("Got %d for h32 %d\n", i, handle );
1310             return (HFILE)i;
1311         }
1312     CloseHandle( handle );
1313     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1314     return HFILE_ERROR;
1315 }
1316
1317
1318 /***********************************************************************
1319  *           DosFileHandleToWin32Handle   (KERNEL32.20)
1320  *
1321  * Return the Win32 handle for a DOS handle.
1322  *
1323  * Note: this is not exactly right, since on Win95 the Win32 handles
1324  *       are on top of DOS handles and we do it the other way
1325  *       around. Should be good enough though.
1326  */
1327 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1328 {
1329     HFILE16 hfile = (HFILE16)handle;
1330     if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles();
1331     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1332     {
1333         SetLastError( ERROR_INVALID_HANDLE );
1334         return INVALID_HANDLE_VALUE;
1335     }
1336     return dos_handles[hfile];
1337 }
1338
1339
1340 /***********************************************************************
1341  *           DisposeLZ32Handle   (KERNEL32.22)
1342  *
1343  * Note: this is not entirely correct, we should only close the
1344  *       32-bit handle and not the 16-bit one, but we cannot do
1345  *       this because of the way our DOS handles are implemented.
1346  *       It shouldn't break anything though.
1347  */
1348 void WINAPI DisposeLZ32Handle( HANDLE handle )
1349 {
1350     int i;
1351
1352     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1353
1354     for (i = 5; i < DOS_TABLE_SIZE; i++)
1355         if (dos_handles[i] == handle)
1356         {
1357             dos_handles[i] = 0;
1358             CloseHandle( handle );
1359             break;
1360         }
1361 }
1362
1363
1364 /***********************************************************************
1365  *           FILE_Dup2
1366  *
1367  * dup2() function for DOS handles.
1368  */
1369 HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 )
1370 {
1371     HANDLE new_handle;
1372
1373     if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles();
1374
1375     if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1])
1376     {
1377         SetLastError( ERROR_INVALID_HANDLE );
1378         return HFILE_ERROR16;
1379     }
1380     if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1],
1381                           GetCurrentProcess(), &new_handle,
1382                           0, FALSE, DUPLICATE_SAME_ACCESS ))
1383         return HFILE_ERROR16;
1384     if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] );
1385     dos_handles[hFile2] = new_handle;
1386     return hFile2;
1387 }
1388
1389
1390 /***********************************************************************
1391  *           _lclose   (KERNEL.81)
1392  */
1393 HFILE16 WINAPI _lclose16( HFILE16 hFile )
1394 {
1395     if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile])
1396     {
1397         SetLastError( ERROR_INVALID_HANDLE );
1398         return HFILE_ERROR16;
1399     }
1400     TRACE("%d (handle32=%d)\n", hFile, dos_handles[hFile] );
1401     CloseHandle( dos_handles[hFile] );
1402     dos_handles[hFile] = 0;
1403     return 0;
1404 }
1405
1406
1407 /***********************************************************************
1408  *           _lclose   (KERNEL32.@)
1409  */
1410 HFILE WINAPI _lclose( HFILE hFile )
1411 {
1412     TRACE("handle %d\n", hFile );
1413     return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
1414 }
1415
1416 /***********************************************************************
1417  *              GetOverlappedResult     (KERNEL32.@)
1418  *
1419  * Check the result of an Asynchronous data transfer from a file.
1420  *
1421  * RETURNS
1422  *   TRUE on success
1423  *   FALSE on failure
1424  *
1425  *  If successful (and relevant) lpTransferred will hold the number of
1426  *   bytes transferred during the async operation.
1427  *
1428  * BUGS
1429  *
1430  * Currently only works for WaitCommEvent, ReadFile, WriteFile
1431  *   with communications ports.
1432  *
1433  */
1434 BOOL WINAPI GetOverlappedResult(
1435     HANDLE hFile,              /* [in] handle of file to check on */
1436     LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped  */
1437     LPDWORD lpTransferred,     /* [in/out] number of bytes transferred  */
1438     BOOL bWait                 /* [in] wait for the transfer to complete ? */
1439 ) {
1440     DWORD r;
1441
1442     TRACE("(%d %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
1443
1444     if(lpOverlapped==NULL)
1445     {
1446         ERR("lpOverlapped was null\n");
1447         return FALSE;
1448     }
1449     if(!lpOverlapped->hEvent)
1450     {
1451         ERR("lpOverlapped->hEvent was null\n");
1452         return FALSE;
1453     }
1454
1455     do {
1456         TRACE("waiting on %p\n",lpOverlapped);
1457         r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
1458         TRACE("wait on %p returned %ld\n",lpOverlapped,r);
1459     } while (r==STATUS_USER_APC);
1460
1461     if(lpTransferred)
1462         *lpTransferred = lpOverlapped->InternalHigh;
1463
1464     SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
1465                    ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
1466
1467     return (r==WAIT_OBJECT_0);
1468 }
1469
1470 /***********************************************************************
1471  *             CancelIo                   (KERNEL32.@)
1472  */
1473 BOOL WINAPI CancelIo(HANDLE handle)
1474 {
1475     async_private *ovp,*t;
1476
1477     TRACE("handle = %x\n",handle);
1478
1479     for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
1480     {
1481         t = ovp->next;
1482         if ( ovp->handle == handle )
1483              cancel_async ( ovp );
1484     }
1485     WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1486     return TRUE;
1487 }
1488
1489 /***********************************************************************
1490  *             FILE_AsyncReadService      (INTERNAL)
1491  *
1492  *  This function is called while the client is waiting on the
1493  *  server, so we can't make any server calls here.
1494  */
1495 static void FILE_AsyncReadService(async_private *ovp)
1496 {
1497     async_fileio *fileio = (async_fileio*) ovp;
1498     LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1499     int result, r;
1500     int already = lpOverlapped->InternalHigh;
1501
1502     TRACE("%p %p\n", lpOverlapped, fileio->buffer );
1503
1504     /* check to see if the data is ready (non-blocking) */
1505
1506     if ( fileio->fd_type == FD_TYPE_SOCKET )
1507         result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1508     else
1509     {
1510         result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
1511                         OVERLAPPED_OFFSET (lpOverlapped) + already);
1512         if ((result < 0) && (errno == ESPIPE))
1513             result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
1514     }
1515
1516     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1517     {
1518         TRACE("Deferred read %d\n",errno);
1519         r = STATUS_PENDING;
1520         goto async_end;
1521     }
1522
1523     /* check to see if the transfer is complete */
1524     if(result<0)
1525     {
1526         r = FILE_GetNtStatus ();
1527         goto async_end;
1528     }
1529
1530     lpOverlapped->InternalHigh += result;
1531     TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1532
1533     if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
1534         r = STATUS_SUCCESS;
1535     else
1536         r = STATUS_PENDING;
1537
1538 async_end:
1539     lpOverlapped->Internal = r;
1540 }
1541
1542 /***********************************************************************
1543  *              FILE_ReadFileEx                (INTERNAL)
1544  */
1545 static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1546                          LPOVERLAPPED overlapped,
1547                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1548                          HANDLE hEvent)
1549 {
1550     async_fileio *ovp;
1551     int fd;
1552     int flags;
1553     enum fd_type type;
1554
1555     TRACE("file %d to buf %p num %ld %p func %p\n",
1556           hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
1557
1558     /* check that there is an overlapped struct */
1559     if (overlapped==NULL)
1560     {
1561         SetLastError(ERROR_INVALID_PARAMETER);
1562         return FALSE;
1563     }
1564
1565     fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
1566     if ( fd < 0 )
1567     {
1568         WARN ( "Couldn't get FD\n" );
1569         return FALSE;
1570     }
1571
1572     ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1573     if(!ovp)
1574     {
1575         TRACE("HeapAlloc Failed\n");
1576         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1577         goto error;
1578     }
1579
1580     ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1581     ovp->async.handle = hFile;
1582     ovp->async.fd = fd;
1583     ovp->async.type = ASYNC_TYPE_READ;
1584     ovp->async.func = FILE_AsyncReadService;
1585     ovp->async.event = hEvent;
1586     ovp->lpOverlapped = overlapped;
1587     ovp->count = bytesToRead;
1588     ovp->completion_func = lpCompletionRoutine;
1589     ovp->buffer = buffer;
1590     ovp->fd_type = type;
1591
1592     return !register_new_async (&ovp->async);
1593
1594 error:
1595     close (fd);
1596     return FALSE;
1597
1598 }
1599
1600 /***********************************************************************
1601  *              ReadFileEx                (KERNEL32.@)
1602  */
1603 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1604                          LPOVERLAPPED overlapped,
1605                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1606 {
1607     overlapped->InternalHigh = 0;
1608     return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
1609 }
1610
1611 static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead)
1612 {
1613     OVERLAPPED ov;
1614     BOOL r = FALSE;
1615
1616     TRACE("%d %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead );
1617
1618     ZeroMemory(&ov, sizeof (OVERLAPPED));
1619     if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0))
1620     {
1621         if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent))
1622         {
1623             r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE);
1624         }
1625     }
1626     CloseHandle(ov.hEvent);
1627     return r;
1628 }
1629
1630 /***********************************************************************
1631  *              ReadFile                (KERNEL32.@)
1632  */
1633 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
1634                         LPDWORD bytesRead, LPOVERLAPPED overlapped )
1635 {
1636     int unix_handle, result, flags;
1637     enum fd_type type;
1638
1639     TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToRead,
1640           bytesRead, overlapped );
1641
1642     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
1643     if (!bytesToRead) return TRUE;
1644
1645     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
1646
1647     if (flags & FD_FLAG_OVERLAPPED)
1648     {
1649         if (unix_handle == -1) return FALSE;
1650         if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1651         {
1652             TRACE("Overlapped not specified or invalid event flag\n");
1653             close(unix_handle);
1654             SetLastError(ERROR_INVALID_PARAMETER);
1655             return FALSE;
1656         }
1657
1658         close(unix_handle);
1659         overlapped->InternalHigh = 0;
1660
1661         if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
1662             return FALSE;
1663
1664         if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
1665         {
1666             if ( GetLastError() == ERROR_IO_INCOMPLETE )
1667                 SetLastError ( ERROR_IO_PENDING );
1668             return FALSE;
1669         }
1670
1671         return TRUE;
1672     }
1673     if (flags & FD_FLAG_TIMEOUT)
1674     {
1675         close(unix_handle);
1676         return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead);
1677     }
1678     switch(type)
1679     {
1680     case FD_TYPE_SMB:
1681         return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
1682
1683     case FD_TYPE_CONSOLE:
1684         return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
1685
1686     case FD_TYPE_DEFAULT:
1687         /* normal unix files */
1688         if (unix_handle == -1) return FALSE;
1689         if (overlapped)
1690         {
1691             DWORD highOffset = overlapped->OffsetHigh;
1692             if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1693                                                              &highOffset, FILE_BEGIN)) &&
1694                  (GetLastError() != NO_ERROR) )
1695             {
1696               close(unix_handle);
1697               return FALSE;
1698             }
1699         }
1700         break;
1701
1702     default:
1703         if (unix_handle == -1)
1704             return FALSE;
1705         if (overlapped)
1706         {
1707             close(unix_handle);
1708             SetLastError(ERROR_INVALID_PARAMETER);
1709             return FALSE;
1710         }
1711         break;
1712     }
1713
1714     /* code for synchronous reads */
1715     while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
1716     {
1717         if ((errno == EAGAIN) || (errno == EINTR)) continue;
1718         if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
1719         FILE_SetDosError();
1720         break;
1721     }
1722     close( unix_handle );
1723     if (result == -1) return FALSE;
1724     if (bytesRead) *bytesRead = result;
1725     return TRUE;
1726 }
1727
1728
1729 /***********************************************************************
1730  *             FILE_AsyncWriteService      (INTERNAL)
1731  *
1732  *  This function is called while the client is waiting on the
1733  *  server, so we can't make any server calls here.
1734  */
1735 static void FILE_AsyncWriteService(struct async_private *ovp)
1736 {
1737     async_fileio *fileio = (async_fileio *) ovp;
1738     LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
1739     int result, r;
1740     int already = lpOverlapped->InternalHigh;
1741
1742     TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
1743
1744     /* write some data (non-blocking) */
1745
1746     if ( fileio->fd_type == FD_TYPE_SOCKET )
1747         result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1748     else
1749     {
1750         result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
1751                     OVERLAPPED_OFFSET (lpOverlapped) + already);
1752         if ((result < 0) && (errno == ESPIPE))
1753             result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
1754     }
1755
1756     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
1757     {
1758         r = STATUS_PENDING;
1759         goto async_end;
1760     }
1761
1762     /* check to see if the transfer is complete */
1763     if(result<0)
1764     {
1765         r = FILE_GetNtStatus ();
1766         goto async_end;
1767     }
1768
1769     lpOverlapped->InternalHigh += result;
1770
1771     TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
1772
1773     if(lpOverlapped->InternalHigh < fileio->count)
1774         r = STATUS_PENDING;
1775     else
1776         r = STATUS_SUCCESS;
1777
1778 async_end:
1779     lpOverlapped->Internal = r;
1780 }
1781
1782 /***********************************************************************
1783  *              FILE_WriteFileEx
1784  */
1785 static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1786                              LPOVERLAPPED overlapped,
1787                              LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1788                              HANDLE hEvent)
1789 {
1790     async_fileio *ovp;
1791     int fd;
1792     int flags;
1793     enum fd_type type;
1794
1795     TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
1796           hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
1797
1798     if (overlapped == NULL)
1799     {
1800         SetLastError(ERROR_INVALID_PARAMETER);
1801         return FALSE;
1802     }
1803
1804     fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
1805     if ( fd < 0 )
1806     {
1807         TRACE( "Couldn't get FD\n" );
1808         return FALSE;
1809     }
1810
1811     ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
1812     if(!ovp)
1813     {
1814         TRACE("HeapAlloc Failed\n");
1815         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1816         goto error;
1817     }
1818
1819     ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
1820     ovp->async.handle = hFile;
1821     ovp->async.fd = fd;
1822     ovp->async.type = ASYNC_TYPE_WRITE;
1823     ovp->async.func = FILE_AsyncWriteService;
1824     ovp->lpOverlapped = overlapped;
1825     ovp->async.event = hEvent;
1826     ovp->buffer = (LPVOID) buffer;
1827     ovp->count = bytesToWrite;
1828     ovp->completion_func = lpCompletionRoutine;
1829     ovp->fd_type = type;
1830
1831     return !register_new_async (&ovp->async);
1832
1833 error:
1834     close (fd);
1835     return FALSE;
1836 }
1837
1838 /***********************************************************************
1839  *              WriteFileEx                (KERNEL32.@)
1840  */
1841 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1842                          LPOVERLAPPED overlapped,
1843                          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
1844 {
1845     overlapped->InternalHigh = 0;
1846
1847     return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
1848 }
1849
1850 /***********************************************************************
1851  *             WriteFile               (KERNEL32.@)
1852  */
1853 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
1854                          LPDWORD bytesWritten, LPOVERLAPPED overlapped )
1855 {
1856     int unix_handle, result, flags;
1857     enum fd_type type;
1858
1859     TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite,
1860           bytesWritten, overlapped );
1861
1862     if (bytesWritten) *bytesWritten = 0;  /* Do this before anything else */
1863     if (!bytesToWrite) return TRUE;
1864
1865     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
1866
1867     if (flags & FD_FLAG_OVERLAPPED)
1868     {
1869         if (unix_handle == -1) return FALSE;
1870         if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) )
1871         {
1872             TRACE("Overlapped not specified or invalid event flag\n");
1873             close(unix_handle);
1874             SetLastError(ERROR_INVALID_PARAMETER);
1875             return FALSE;
1876         }
1877
1878         close(unix_handle);
1879         overlapped->InternalHigh = 0;
1880
1881         if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent))
1882             return FALSE;
1883
1884         if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
1885         {
1886             if ( GetLastError() == ERROR_IO_INCOMPLETE )
1887                 SetLastError ( ERROR_IO_PENDING );
1888             return FALSE;
1889         }
1890
1891         return TRUE;
1892     }
1893
1894     switch(type)
1895     {
1896     case FD_TYPE_CONSOLE:
1897         TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
1898               bytesWritten, overlapped );
1899         return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
1900
1901     case FD_TYPE_DEFAULT:
1902         if (unix_handle == -1) return FALSE;
1903
1904         if(overlapped)
1905         {
1906             DWORD highOffset = overlapped->OffsetHigh;
1907             if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset,
1908                                                              &highOffset, FILE_BEGIN)) &&
1909                  (GetLastError() != NO_ERROR) )
1910             {
1911               close(unix_handle);
1912               return FALSE;
1913             }
1914         }
1915         break;
1916
1917     default:
1918         if (unix_handle == -1)
1919             return FALSE;
1920         if (overlapped)
1921         {
1922             close(unix_handle);
1923             SetLastError(ERROR_INVALID_PARAMETER);
1924             return FALSE;
1925         }
1926         break;
1927     }
1928
1929     /* synchronous file write */
1930     while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
1931     {
1932         if ((errno == EAGAIN) || (errno == EINTR)) continue;
1933         if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue;
1934         if (errno == ENOSPC)
1935             SetLastError( ERROR_DISK_FULL );
1936         else
1937         FILE_SetDosError();
1938         break;
1939     }
1940     close( unix_handle );
1941     if (result == -1) return FALSE;
1942     if (bytesWritten) *bytesWritten = result;
1943     return TRUE;
1944 }
1945
1946
1947 /***********************************************************************
1948  *           _hread (KERNEL.349)
1949  */
1950 LONG WINAPI WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
1951 {
1952     LONG maxlen;
1953
1954     TRACE("%d %08lx %ld\n",
1955                   hFile, (DWORD)buffer, count );
1956
1957     /* Some programs pass a count larger than the allocated buffer */
1958     maxlen = GetSelectorLimit16( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
1959     if (count > maxlen) count = maxlen;
1960     return _lread((HFILE)DosFileHandleToWin32Handle(hFile), MapSL(buffer), count );
1961 }
1962
1963
1964 /***********************************************************************
1965  *           _lread (KERNEL.82)
1966  */
1967 UINT16 WINAPI WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
1968 {
1969     return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
1970 }
1971
1972
1973 /***********************************************************************
1974  *           _lread   (KERNEL32.@)
1975  */
1976 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
1977 {
1978     DWORD result;
1979     if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL )) return -1;
1980     return result;
1981 }
1982
1983
1984 /***********************************************************************
1985  *           _lread16   (KERNEL.82)
1986  */
1987 UINT16 WINAPI _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
1988 {
1989     return (UINT16)_lread((HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
1990 }
1991
1992
1993 /***********************************************************************
1994  *           _lcreat   (KERNEL.83)
1995  */
1996 HFILE16 WINAPI _lcreat16( LPCSTR path, INT16 attr )
1997 {
1998     return Win32HandleToDosFileHandle( (HANDLE)_lcreat( path, attr ) );
1999 }
2000
2001
2002 /***********************************************************************
2003  *           _lcreat   (KERNEL32.@)
2004  */
2005 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
2006 {
2007     /* Mask off all flags not explicitly allowed by the doc */
2008     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2009     TRACE("%s %02x\n", path, attr );
2010     return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
2011                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2012                                CREATE_ALWAYS, attr, 0 );
2013 }
2014
2015
2016 /***********************************************************************
2017  *           SetFilePointer   (KERNEL32.@)
2018  */
2019 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword,
2020                              DWORD method )
2021 {
2022     DWORD ret = INVALID_SET_FILE_POINTER;
2023
2024     TRACE("handle %d offset %ld high %ld origin %ld\n",
2025           hFile, distance, highword?*highword:0, method );
2026
2027     SERVER_START_REQ( set_file_pointer )
2028     {
2029         req->handle = hFile;
2030         req->low = distance;
2031         req->high = highword ? *highword : (distance >= 0) ? 0 : -1;
2032         /* FIXME: assumes 1:1 mapping between Windows and Unix seek constants */
2033         req->whence = method;
2034         SetLastError( 0 );
2035         if (!wine_server_call_err( req ))
2036         {
2037             ret = reply->new_low;
2038             if (highword) *highword = reply->new_high;
2039         }
2040     }
2041     SERVER_END_REQ;
2042     return ret;
2043 }
2044
2045
2046 /***********************************************************************
2047  *           _llseek   (KERNEL.84)
2048  *
2049  * FIXME:
2050  *   Seeking before the start of the file should be allowed for _llseek16,
2051  *   but cause subsequent I/O operations to fail (cf. interrupt list)
2052  *
2053  */
2054 LONG WINAPI _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
2055 {
2056     return SetFilePointer( DosFileHandleToWin32Handle(hFile), lOffset, NULL, nOrigin );
2057 }
2058
2059
2060 /***********************************************************************
2061  *           _llseek   (KERNEL32.@)
2062  */
2063 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
2064 {
2065     return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
2066 }
2067
2068
2069 /***********************************************************************
2070  *           _lopen   (KERNEL.85)
2071  */
2072 HFILE16 WINAPI _lopen16( LPCSTR path, INT16 mode )
2073 {
2074     return Win32HandleToDosFileHandle( (HANDLE)_lopen( path, mode ) );
2075 }
2076
2077
2078 /***********************************************************************
2079  *           _lopen   (KERNEL32.@)
2080  */
2081 HFILE WINAPI _lopen( LPCSTR path, INT mode )
2082 {
2083     DWORD access, sharing;
2084
2085     TRACE("('%s',%04x)\n", path, mode );
2086     FILE_ConvertOFMode( mode, &access, &sharing );
2087     return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
2088 }
2089
2090
2091 /***********************************************************************
2092  *           _lwrite   (KERNEL.86)
2093  */
2094 UINT16 WINAPI _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
2095 {
2096     return (UINT16)_hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, (LONG)count );
2097 }
2098
2099 /***********************************************************************
2100  *           _lwrite   (KERNEL32.@)
2101  */
2102 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
2103 {
2104     return (UINT)_hwrite( hFile, buffer, (LONG)count );
2105 }
2106
2107
2108 /***********************************************************************
2109  *           _hread16   (KERNEL.349)
2110  */
2111 LONG WINAPI _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
2112 {
2113     return _lread( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2114 }
2115
2116
2117 /***********************************************************************
2118  *           _hread   (KERNEL32.@)
2119  */
2120 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
2121 {
2122     return _lread( hFile, buffer, count );
2123 }
2124
2125
2126 /***********************************************************************
2127  *           _hwrite   (KERNEL.350)
2128  */
2129 LONG WINAPI _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
2130 {
2131     return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count );
2132 }
2133
2134
2135 /***********************************************************************
2136  *           _hwrite   (KERNEL32.@)
2137  *
2138  *      experimentation yields that _lwrite:
2139  *              o truncates the file at the current position with
2140  *                a 0 len write
2141  *              o returns 0 on a 0 length write
2142  *              o works with console handles
2143  *
2144  */
2145 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
2146 {
2147     DWORD result;
2148
2149     TRACE("%d %p %ld\n", handle, buffer, count );
2150
2151     if (!count)
2152     {
2153         /* Expand or truncate at current position */
2154         if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
2155         return 0;
2156     }
2157     if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
2158         return HFILE_ERROR;
2159     return result;
2160 }
2161
2162
2163 /***********************************************************************
2164  *           SetHandleCount   (KERNEL.199)
2165  */
2166 UINT16 WINAPI SetHandleCount16( UINT16 count )
2167 {
2168     return SetHandleCount( count );
2169 }
2170
2171
2172 /*************************************************************************
2173  *           SetHandleCount   (KERNEL32.@)
2174  */
2175 UINT WINAPI SetHandleCount( UINT count )
2176 {
2177     return min( 256, count );
2178 }
2179
2180
2181 /***********************************************************************
2182  *           FlushFileBuffers   (KERNEL32.@)
2183  */
2184 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
2185 {
2186     BOOL ret;
2187     SERVER_START_REQ( flush_file )
2188     {
2189         req->handle = hFile;
2190         ret = !wine_server_call_err( req );
2191     }
2192     SERVER_END_REQ;
2193     return ret;
2194 }
2195
2196
2197 /**************************************************************************
2198  *           SetEndOfFile   (KERNEL32.@)
2199  */
2200 BOOL WINAPI SetEndOfFile( HANDLE hFile )
2201 {
2202     BOOL ret;
2203     SERVER_START_REQ( truncate_file )
2204     {
2205         req->handle = hFile;
2206         ret = !wine_server_call_err( req );
2207     }
2208     SERVER_END_REQ;
2209     return ret;
2210 }
2211
2212
2213 /***********************************************************************
2214  *           DeleteFile   (KERNEL.146)
2215  */
2216 BOOL16 WINAPI DeleteFile16( LPCSTR path )
2217 {
2218     return DeleteFileA( path );
2219 }
2220
2221
2222 /***********************************************************************
2223  *           DeleteFileA   (KERNEL32.@)
2224  */
2225 BOOL WINAPI DeleteFileA( LPCSTR path )
2226 {
2227     DOS_FULL_NAME full_name;
2228     HANDLE hFile;
2229
2230     if (!path)
2231     {
2232         SetLastError(ERROR_INVALID_PARAMETER);
2233         return FALSE;
2234     }
2235     TRACE("'%s'\n", path );
2236
2237     if (!*path)
2238     {
2239         ERR("Empty path passed\n");
2240         return FALSE;
2241     }
2242     if (DOSFS_GetDevice( path ))
2243     {
2244         WARN("cannot remove DOS device '%s'!\n", path);
2245         SetLastError( ERROR_FILE_NOT_FOUND );
2246         return FALSE;
2247     }
2248
2249     if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
2250
2251     /* check if we are allowed to delete the source */
2252     hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2253                              NULL, OPEN_EXISTING, 0, 0, TRUE,
2254                              GetDriveTypeA( full_name.short_name ) );
2255     if (!hFile) return FALSE;
2256
2257     if (unlink( full_name.long_name ) == -1)
2258     {
2259         FILE_SetDosError();
2260         CloseHandle(hFile);
2261         return FALSE;
2262     }
2263     CloseHandle(hFile);
2264     return TRUE;
2265 }
2266
2267
2268 /***********************************************************************
2269  *           DeleteFileW   (KERNEL32.@)
2270  */
2271 BOOL WINAPI DeleteFileW( LPCWSTR path )
2272 {
2273     LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
2274     BOOL ret = DeleteFileA( xpath );
2275     HeapFree( GetProcessHeap(), 0, xpath );
2276     return ret;
2277 }
2278
2279
2280 /***********************************************************************
2281  *           GetFileType   (KERNEL32.@)
2282  */
2283 DWORD WINAPI GetFileType( HANDLE hFile )
2284 {
2285     DWORD ret = FILE_TYPE_UNKNOWN;
2286     SERVER_START_REQ( get_file_info )
2287     {
2288         req->handle = hFile;
2289         if (!wine_server_call_err( req )) ret = reply->type;
2290     }
2291     SERVER_END_REQ;
2292     return ret;
2293 }
2294
2295
2296 /* check if a file name is for an executable file (.exe or .com) */
2297 inline static BOOL is_executable( const char *name )
2298 {
2299     int len = strlen(name);
2300
2301     if (len < 4) return FALSE;
2302     return (!strcasecmp( name + len - 4, ".exe" ) ||
2303             !strcasecmp( name + len - 4, ".com" ));
2304 }
2305
2306
2307 /***********************************************************************
2308  *           FILE_AddBootRenameEntry
2309  *
2310  * Adds an entry to the registry that is loaded when windows boots and
2311  * checks if there are some files to be removed or renamed/moved.
2312  * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
2313  * non-NULL then the file is moved, otherwise it is deleted.  The
2314  * entry of the registrykey is always appended with two zero
2315  * terminated strings. If <fn2> is NULL then the second entry is
2316  * simply a single 0-byte. Otherwise the second filename goes
2317  * there. The entries are prepended with \??\ before the path and the
2318  * second filename gets also a '!' as the first character if
2319  * MOVEFILE_REPLACE_EXISTING is set. After the final string another
2320  * 0-byte follows to indicate the end of the strings.
2321  * i.e.:
2322  * \??\D:\test\file1[0]
2323  * !\??\D:\test\file1_renamed[0]
2324  * \??\D:\Test|delete[0]
2325  * [0]                        <- file is to be deleted, second string empty
2326  * \??\D:\test\file2[0]
2327  * !\??\D:\test\file2_renamed[0]
2328  * [0]                        <- indicates end of strings
2329  *
2330  * or:
2331  * \??\D:\test\file1[0]
2332  * !\??\D:\test\file1_renamed[0]
2333  * \??\D:\Test|delete[0]
2334  * [0]                        <- file is to be deleted, second string empty
2335  * [0]                        <- indicates end of strings
2336  *
2337  */
2338 static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
2339 {
2340     static const char PreString[] = "\\??\\";
2341     static const char ValueName[] = "PendingFileRenameOperations";
2342
2343     BOOL rc = FALSE;
2344     HKEY Reboot = 0;
2345     DWORD Type, len1, len2, l;
2346     DWORD DataSize = 0;
2347     BYTE *Buffer = NULL;
2348
2349     if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
2350                      &Reboot) != ERROR_SUCCESS)
2351     {
2352         WARN("Error creating key for reboot managment [%s]\n",
2353              "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
2354         return FALSE;
2355     }
2356
2357     l = strlen(PreString);
2358     len1 = strlen(fn1) + l + 1;
2359     if (fn2)
2360     {
2361         len2 = strlen(fn2) + l + 1;
2362         if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
2363     }
2364     else len2 = 1; /* minimum is the 0 byte for the empty second string */
2365
2366     /* First we check if the key exists and if so how many bytes it already contains. */
2367     if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
2368     {
2369         if (Type != REG_MULTI_SZ) goto Quit;
2370         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
2371         if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
2372             goto Quit;
2373         if (DataSize) DataSize--;  /* remove terminating null (will be added back later) */
2374     }
2375     else
2376     {
2377         if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
2378         DataSize = 0;
2379     }
2380     sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
2381     DataSize += len1;
2382     if (fn2)
2383     {
2384         sprintf( Buffer + DataSize, "%s%s%s",
2385                  (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
2386         DataSize += len2;
2387     }
2388     else Buffer[DataSize++] = 0;
2389
2390     Buffer[DataSize++] = 0;  /* add final null */
2391     rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
2392
2393  Quit:
2394     if (Reboot) RegCloseKey(Reboot);
2395     if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
2396     return(rc);
2397 }
2398
2399
2400 /**************************************************************************
2401  *           MoveFileExA   (KERNEL32.@)
2402  */
2403 BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag )
2404 {
2405     DOS_FULL_NAME full_name1, full_name2;
2406     HANDLE hFile;
2407
2408     TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
2409
2410     /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
2411        In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
2412        to be really compatible. Most programs wont have any problems though. In case
2413        you encounter one, this is what you should return here. I don't know what's up
2414        with NT 3.5. Is this function available there or not?
2415        Does anybody really care about 3.5? :)
2416     */
2417
2418     /* Filename1 has to be always set to a valid path. Filename2 may be NULL
2419        if the source file has to be deleted.
2420     */
2421     if (!fn1) {
2422         SetLastError(ERROR_INVALID_PARAMETER);
2423         return FALSE;
2424     }
2425
2426     /* This function has to be run through in order to process the name properly.
2427        If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
2428        that is the behaviour on NT 4.0. The operation accepts the filenames as
2429        they are given but it can't reply with a reasonable returncode. Success
2430        means in that case success for entering the values into the registry.
2431     */
2432     if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
2433     {
2434         if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2435             return FALSE;
2436     }
2437
2438     if (fn2)  /* !fn2 means delete fn1 */
2439     {
2440         if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
2441         {
2442             if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2443             {
2444                 /* target exists, check if we may overwrite */
2445                 if (!(flag & MOVEFILE_REPLACE_EXISTING))
2446                 {
2447                     /* FIXME: Use right error code */
2448                     SetLastError( ERROR_ACCESS_DENIED );
2449                     return FALSE;
2450                 }
2451             }
2452         }
2453         else
2454         {
2455             if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
2456             {
2457                 if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
2458                     return FALSE;
2459             }
2460         }
2461
2462         /* Source name and target path are valid */
2463
2464         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2465         {
2466             /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2467                Perhaps we should queue these command and execute it
2468                when exiting... What about using on_exit(2)
2469             */
2470             FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
2471                   fn1, fn2);
2472             return FILE_AddBootRenameEntry( fn1, fn2, flag );
2473         }
2474
2475         /* check if we are allowed to delete the source */
2476         hFile = FILE_CreateFile( full_name1.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2477                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2478                                  GetDriveTypeA( full_name1.short_name ) );
2479         if (!hFile) return FALSE;
2480         CloseHandle(hFile);
2481
2482         /* check, if we are allowed to delete the destination,
2483         **     (but the file not being there is fine) */
2484         hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
2485                                  NULL, OPEN_EXISTING, 0, 0, TRUE,
2486                                  GetDriveTypeA( full_name2.short_name ) );
2487         if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
2488         CloseHandle(hFile);
2489
2490         if (full_name1.drive != full_name2.drive)
2491         {
2492             /* use copy, if allowed */
2493             if (!(flag & MOVEFILE_COPY_ALLOWED))
2494             {
2495                 /* FIXME: Use right error code */
2496                 SetLastError( ERROR_FILE_EXISTS );
2497                 return FALSE;
2498             }
2499             return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) );
2500         }
2501         if (rename( full_name1.long_name, full_name2.long_name ) == -1)
2502         {
2503             FILE_SetDosError();
2504             return FALSE;
2505         }
2506         if (is_executable( full_name1.long_name ) != is_executable( full_name2.long_name ))
2507         {
2508             struct stat fstat;
2509             if (stat( full_name2.long_name, &fstat ) != -1)
2510             {
2511                 if (is_executable( full_name2.long_name ))
2512                     /* set executable bit where read bit is set */
2513                     fstat.st_mode |= (fstat.st_mode & 0444) >> 2;
2514                 else
2515                     fstat.st_mode &= ~0111;
2516                 chmod( full_name2.long_name, fstat.st_mode );
2517             }
2518         }
2519         return TRUE;
2520     }
2521     else /* fn2 == NULL means delete source */
2522     {
2523         if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
2524         {
2525             if (flag & MOVEFILE_COPY_ALLOWED) {
2526                 WARN("Illegal flag\n");
2527                 SetLastError( ERROR_GEN_FAILURE );
2528                 return FALSE;
2529             }
2530             /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
2531                Perhaps we should queue these command and execute it
2532                when exiting... What about using on_exit(2)
2533             */
2534             FIXME("Please delete file '%s' when Wine has finished\n", fn1);
2535             return FILE_AddBootRenameEntry( fn1, NULL, flag );
2536         }
2537
2538         if (unlink( full_name1.long_name ) == -1)
2539         {
2540             FILE_SetDosError();
2541             return FALSE;
2542         }
2543         return TRUE; /* successfully deleted */
2544     }
2545 }
2546
2547 /**************************************************************************
2548  *           MoveFileExW   (KERNEL32.@)
2549  */
2550 BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
2551 {
2552     LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2553     LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2554     BOOL res = MoveFileExA( afn1, afn2, flag );
2555     HeapFree( GetProcessHeap(), 0, afn1 );
2556     HeapFree( GetProcessHeap(), 0, afn2 );
2557     return res;
2558 }
2559
2560
2561 /**************************************************************************
2562  *           MoveFileA   (KERNEL32.@)
2563  *
2564  *  Move file or directory
2565  */
2566 BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 )
2567 {
2568     DOS_FULL_NAME full_name1, full_name2;
2569     struct stat fstat;
2570
2571     TRACE("(%s,%s)\n", fn1, fn2 );
2572
2573     if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
2574     if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))  {
2575       /* The new name must not already exist */
2576       SetLastError(ERROR_ALREADY_EXISTS);
2577       return FALSE;
2578     }
2579     if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
2580
2581     if (full_name1.drive == full_name2.drive) /* move */
2582         return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED );
2583
2584     /* copy */
2585     if (stat( full_name1.long_name, &fstat ))
2586     {
2587         WARN("Invalid source file %s\n",
2588              full_name1.long_name);
2589         FILE_SetDosError();
2590         return FALSE;
2591     }
2592     if (S_ISDIR(fstat.st_mode)) {
2593         /* No Move for directories across file systems */
2594         /* FIXME: Use right error code */
2595         SetLastError( ERROR_GEN_FAILURE );
2596         return FALSE;
2597     }
2598     return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */
2599 }
2600
2601
2602 /**************************************************************************
2603  *           MoveFileW   (KERNEL32.@)
2604  */
2605 BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 )
2606 {
2607     LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
2608     LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
2609     BOOL res = MoveFileA( afn1, afn2 );
2610     HeapFree( GetProcessHeap(), 0, afn1 );
2611     HeapFree( GetProcessHeap(), 0, afn2 );
2612     return res;
2613 }
2614
2615
2616 /**************************************************************************
2617  *           CopyFileA   (KERNEL32.@)
2618  */
2619 BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists )
2620 {
2621     HANDLE h1, h2;
2622     BY_HANDLE_FILE_INFORMATION info;
2623     DWORD count;
2624     BOOL ret = FALSE;
2625     int mode;
2626     char buffer[2048];
2627
2628     if ((h1 = CreateFileA( source, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
2629                            OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
2630         return FALSE;
2631     if (!GetFileInformationByHandle( h1, &info ))
2632     {
2633         CloseHandle( h1 );
2634         return FALSE;
2635     }
2636     mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
2637     if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2638                              fail_if_exists ? CREATE_NEW : CREATE_ALWAYS,
2639                              info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
2640     {
2641         CloseHandle( h1 );
2642         return FALSE;
2643     }
2644
2645     while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count > 0)
2646     {
2647         char *p = buffer;
2648         while (count > 0)
2649         {
2650             DWORD res;
2651             if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
2652             p += res;
2653             count -= res;
2654         }
2655     }
2656     ret =  TRUE;
2657 done:
2658     CloseHandle( h1 );
2659     CloseHandle( h2 );
2660     return ret;
2661 }
2662
2663
2664 /**************************************************************************
2665  *           CopyFileW   (KERNEL32.@)
2666  */
2667 BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists)
2668 {
2669     LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
2670     LPSTR destA   = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
2671     BOOL ret = CopyFileA( sourceA, destA, fail_if_exists );
2672     HeapFree( GetProcessHeap(), 0, sourceA );
2673     HeapFree( GetProcessHeap(), 0, destA );
2674     return ret;
2675 }
2676
2677
2678 /**************************************************************************
2679  *           CopyFileExA   (KERNEL32.@)
2680  *
2681  * This implementation ignores most of the extra parameters passed-in into
2682  * the "ex" version of the method and calls the CopyFile method.
2683  * It will have to be fixed eventually.
2684  */
2685 BOOL WINAPI CopyFileExA(LPCSTR             sourceFilename,
2686                            LPCSTR             destFilename,
2687                            LPPROGRESS_ROUTINE progressRoutine,
2688                            LPVOID             appData,
2689                            LPBOOL           cancelFlagPointer,
2690                            DWORD              copyFlags)
2691 {
2692   BOOL failIfExists = FALSE;
2693
2694   /*
2695    * Interpret the only flag that CopyFile can interpret.
2696    */
2697   if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0)
2698   {
2699     failIfExists = TRUE;
2700   }
2701
2702   return CopyFileA(sourceFilename, destFilename, failIfExists);
2703 }
2704
2705 /**************************************************************************
2706  *           CopyFileExW   (KERNEL32.@)
2707  */
2708 BOOL WINAPI CopyFileExW(LPCWSTR            sourceFilename,
2709                            LPCWSTR            destFilename,
2710                            LPPROGRESS_ROUTINE progressRoutine,
2711                            LPVOID             appData,
2712                            LPBOOL           cancelFlagPointer,
2713                            DWORD              copyFlags)
2714 {
2715     LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename );
2716     LPSTR destA   = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename );
2717
2718     BOOL ret = CopyFileExA(sourceA,
2719                               destA,
2720                               progressRoutine,
2721                               appData,
2722                               cancelFlagPointer,
2723                               copyFlags);
2724
2725     HeapFree( GetProcessHeap(), 0, sourceA );
2726     HeapFree( GetProcessHeap(), 0, destA );
2727
2728     return ret;
2729 }
2730
2731
2732 /***********************************************************************
2733  *              SetFileTime   (KERNEL32.@)
2734  */
2735 BOOL WINAPI SetFileTime( HANDLE hFile,
2736                            const FILETIME *lpCreationTime,
2737                            const FILETIME *lpLastAccessTime,
2738                            const FILETIME *lpLastWriteTime )
2739 {
2740     BOOL ret;
2741     SERVER_START_REQ( set_file_time )
2742     {
2743         req->handle = hFile;
2744         if (lpLastAccessTime)
2745             RtlTimeToSecondsSince1970( lpLastAccessTime, (DWORD *)&req->access_time );
2746         else
2747             req->access_time = 0; /* FIXME */
2748         if (lpLastWriteTime)
2749             RtlTimeToSecondsSince1970( lpLastWriteTime, (DWORD *)&req->write_time );
2750         else
2751             req->write_time = 0; /* FIXME */
2752         ret = !wine_server_call_err( req );
2753     }
2754     SERVER_END_REQ;
2755     return ret;
2756 }
2757
2758
2759 /**************************************************************************
2760  *           LockFile   (KERNEL32.@)
2761  */
2762 BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2763                         DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh )
2764 {
2765     BOOL ret;
2766
2767     FIXME("not implemented in server\n");
2768
2769     SERVER_START_REQ( lock_file )
2770     {
2771         req->handle      = hFile;
2772         req->offset_low  = dwFileOffsetLow;
2773         req->offset_high = dwFileOffsetHigh;
2774         req->count_low   = nNumberOfBytesToLockLow;
2775         req->count_high  = nNumberOfBytesToLockHigh;
2776         ret = !wine_server_call_err( req );
2777     }
2778     SERVER_END_REQ;
2779     return ret;
2780 }
2781
2782 /**************************************************************************
2783  * LockFileEx [KERNEL32.@]
2784  *
2785  * Locks a byte range within an open file for shared or exclusive access.
2786  *
2787  * RETURNS
2788  *   success: TRUE
2789  *   failure: FALSE
2790  *
2791  * NOTES
2792  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
2793  */
2794 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
2795                       DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
2796                       LPOVERLAPPED pOverlapped )
2797 {
2798     FIXME("hFile=%d,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2799           hFile, flags, reserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh,
2800           pOverlapped);
2801     if (reserved == 0)
2802         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2803     else
2804     {
2805         ERR("reserved == %ld: Supposed to be 0??\n", reserved);
2806         SetLastError(ERROR_INVALID_PARAMETER);
2807     }
2808
2809     return FALSE;
2810 }
2811
2812
2813 /**************************************************************************
2814  *           UnlockFile   (KERNEL32.@)
2815  */
2816 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2817                           DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh )
2818 {
2819     BOOL ret;
2820
2821     FIXME("not implemented in server\n");
2822
2823     SERVER_START_REQ( unlock_file )
2824     {
2825         req->handle      = hFile;
2826         req->offset_low  = dwFileOffsetLow;
2827         req->offset_high = dwFileOffsetHigh;
2828         req->count_low   = nNumberOfBytesToUnlockLow;
2829         req->count_high  = nNumberOfBytesToUnlockHigh;
2830         ret = !wine_server_call_err( req );
2831     }
2832     SERVER_END_REQ;
2833     return ret;
2834 }
2835
2836
2837 /**************************************************************************
2838  *           UnlockFileEx   (KERNEL32.@)
2839  */
2840 BOOL WINAPI UnlockFileEx(
2841                 HANDLE hFile,
2842                 DWORD dwReserved,
2843                 DWORD nNumberOfBytesToUnlockLow,
2844                 DWORD nNumberOfBytesToUnlockHigh,
2845                 LPOVERLAPPED lpOverlapped
2846 )
2847 {
2848         FIXME("hFile=%d,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.\n",
2849           hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh,
2850           lpOverlapped);
2851         if (dwReserved == 0)
2852                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2853         else
2854         {
2855                 ERR("reserved == %ld: Supposed to be 0??\n", dwReserved);
2856                 SetLastError(ERROR_INVALID_PARAMETER);
2857         }
2858
2859         return FALSE;
2860 }
2861
2862
2863 #if 0
2864
2865 struct DOS_FILE_LOCK {
2866   struct DOS_FILE_LOCK *        next;
2867   DWORD                         base;
2868   DWORD                         len;
2869   DWORD                         processId;
2870   FILE_OBJECT *                 dos_file;
2871 /*  char *                      unix_name;*/
2872 };
2873
2874 typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
2875
2876 static DOS_FILE_LOCK *locks = NULL;
2877 static void DOS_RemoveFileLocks(FILE_OBJECT *file);
2878
2879
2880 /* Locks need to be mirrored because unix file locking is based
2881  * on the pid. Inside of wine there can be multiple WINE processes
2882  * that share the same unix pid.
2883  * Read's and writes should check these locks also - not sure
2884  * how critical that is at this point (FIXME).
2885  */
2886
2887 static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
2888 {
2889   DOS_FILE_LOCK *curr;
2890   DWORD         processId;
2891
2892   processId = GetCurrentProcessId();
2893
2894   /* check if lock overlaps a current lock for the same file */
2895 #if 0
2896   for (curr = locks; curr; curr = curr->next) {
2897     if (strcmp(curr->unix_name, file->unix_name) == 0) {
2898       if ((f->l_start == curr->base) && (f->l_len == curr->len))
2899         return TRUE;/* region is identic */
2900       if ((f->l_start < (curr->base + curr->len)) &&
2901           ((f->l_start + f->l_len) > curr->base)) {
2902         /* region overlaps */
2903         return FALSE;
2904       }
2905     }
2906   }
2907 #endif
2908
2909   curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
2910   curr->processId = GetCurrentProcessId();
2911   curr->base = f->l_start;
2912   curr->len = f->l_len;
2913 /*  curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
2914   curr->next = locks;
2915   curr->dos_file = file;
2916   locks = curr;
2917   return TRUE;
2918 }
2919
2920 static void DOS_RemoveFileLocks(FILE_OBJECT *file)
2921 {
2922   DWORD         processId;
2923   DOS_FILE_LOCK **curr;
2924   DOS_FILE_LOCK *rem;
2925
2926   processId = GetCurrentProcessId();
2927   curr = &locks;
2928   while (*curr) {
2929     if ((*curr)->dos_file == file) {
2930       rem = *curr;
2931       *curr = (*curr)->next;
2932 /*      HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2933       HeapFree( GetProcessHeap(), 0, rem );
2934     }
2935     else
2936       curr = &(*curr)->next;
2937   }
2938 }
2939
2940 static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
2941 {
2942   DWORD         processId;
2943   DOS_FILE_LOCK **curr;
2944   DOS_FILE_LOCK *rem;
2945
2946   processId = GetCurrentProcessId();
2947   for (curr = &locks; *curr; curr = &(*curr)->next) {
2948     if ((*curr)->processId == processId &&
2949         (*curr)->dos_file == file &&
2950         (*curr)->base == f->l_start &&
2951         (*curr)->len == f->l_len) {
2952       /* this is the same lock */
2953       rem = *curr;
2954       *curr = (*curr)->next;
2955 /*      HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
2956       HeapFree( GetProcessHeap(), 0, rem );
2957       return TRUE;
2958     }
2959   }
2960   /* no matching lock found */
2961   return FALSE;
2962 }
2963
2964
2965 /**************************************************************************
2966  *           LockFile   (KERNEL32.@)
2967  */
2968 BOOL WINAPI LockFile(
2969         HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
2970         DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
2971 {
2972   struct flock f;
2973   FILE_OBJECT *file;
2974
2975   TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
2976                hFile, dwFileOffsetLow, dwFileOffsetHigh,
2977                nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
2978
2979   if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
2980     FIXME("Unimplemented bytes > 32bits\n");
2981     return FALSE;
2982   }
2983
2984   f.l_start = dwFileOffsetLow;
2985   f.l_len = nNumberOfBytesToLockLow;
2986   f.l_whence = SEEK_SET;
2987   f.l_pid = 0;
2988   f.l_type = F_WRLCK;
2989
2990   if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
2991
2992   /* shadow locks internally */
2993   if (!DOS_AddLock(file, &f)) {
2994     SetLastError( ERROR_LOCK_VIOLATION );
2995     return FALSE;
2996   }
2997
2998   /* FIXME: Unix locking commented out for now, doesn't work with Excel */
2999 #ifdef USE_UNIX_LOCKS
3000   if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3001     if (errno == EACCES || errno == EAGAIN) {
3002       SetLastError( ERROR_LOCK_VIOLATION );
3003     }
3004     else {
3005       FILE_SetDosError();
3006     }
3007     /* remove our internal copy of the lock */
3008     DOS_RemoveLock(file, &f);
3009     return FALSE;
3010   }
3011 #endif
3012   return TRUE;
3013 }
3014
3015
3016 /**************************************************************************
3017  *           UnlockFile   (KERNEL32.@)
3018  */
3019 BOOL WINAPI UnlockFile(
3020         HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
3021         DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
3022 {
3023   FILE_OBJECT *file;
3024   struct flock f;
3025
3026   TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
3027                hFile, dwFileOffsetLow, dwFileOffsetHigh,
3028                nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
3029
3030   if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
3031     WARN("Unimplemented bytes > 32bits\n");
3032     return FALSE;
3033   }
3034
3035   f.l_start = dwFileOffsetLow;
3036   f.l_len = nNumberOfBytesToUnlockLow;
3037   f.l_whence = SEEK_SET;
3038   f.l_pid = 0;
3039   f.l_type = F_UNLCK;
3040
3041   if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
3042
3043   DOS_RemoveLock(file, &f);     /* ok if fails - may be another wine */
3044
3045   /* FIXME: Unix locking commented out for now, doesn't work with Excel */
3046 #ifdef USE_UNIX_LOCKS
3047   if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
3048     FILE_SetDosError();
3049     return FALSE;
3050   }
3051 #endif
3052   return TRUE;
3053 }
3054 #endif
3055
3056 /**************************************************************************
3057  * GetFileAttributesExA [KERNEL32.@]
3058  */
3059 BOOL WINAPI GetFileAttributesExA(
3060         LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3061         LPVOID lpFileInformation)
3062 {
3063     DOS_FULL_NAME full_name;
3064     BY_HANDLE_FILE_INFORMATION info;
3065
3066     if (lpFileName == NULL) return FALSE;
3067     if (lpFileInformation == NULL) return FALSE;
3068
3069     if (fInfoLevelId == GetFileExInfoStandard) {
3070         LPWIN32_FILE_ATTRIBUTE_DATA lpFad =
3071             (LPWIN32_FILE_ATTRIBUTE_DATA) lpFileInformation;
3072         if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE;
3073         if (!FILE_Stat( full_name.long_name, &info )) return FALSE;
3074
3075         lpFad->dwFileAttributes = info.dwFileAttributes;
3076         lpFad->ftCreationTime   = info.ftCreationTime;
3077         lpFad->ftLastAccessTime = info.ftLastAccessTime;
3078         lpFad->ftLastWriteTime  = info.ftLastWriteTime;
3079         lpFad->nFileSizeHigh    = info.nFileSizeHigh;
3080         lpFad->nFileSizeLow     = info.nFileSizeLow;
3081     }
3082     else {
3083         FIXME("invalid info level %d!\n", fInfoLevelId);
3084         return FALSE;
3085     }
3086
3087     return TRUE;
3088 }
3089
3090
3091 /**************************************************************************
3092  * GetFileAttributesExW [KERNEL32.@]
3093  */
3094 BOOL WINAPI GetFileAttributesExW(
3095         LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
3096         LPVOID lpFileInformation)
3097 {
3098     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName );
3099     BOOL res =
3100         GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation);
3101     HeapFree( GetProcessHeap(), 0, nameA );
3102     return res;
3103 }