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