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