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