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