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