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