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