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