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