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