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