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