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