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