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