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