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