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