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