Release 970112
[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/stat.h>
17 #include <time.h>
18 #include <unistd.h>
19 #include <utime.h>
20
21 #include "windows.h"
22 #include "winerror.h"
23 #include "drive.h"
24 #include "file.h"
25 #include "global.h"
26 #include "heap.h"
27 #include "msdos.h"
28 #include "options.h"
29 #include "ldt.h"
30 #include "process.h"
31 #include "task.h"
32 #include "stddebug.h"
33 #include "debug.h"
34
35
36 typedef struct
37 {
38     K32OBJ    header;
39     int       unix_handle;
40     int       mode;
41     char     *unix_name;
42     DWORD     type;         /* Type for win32 apps */
43 } DOS_FILE;
44
45
46 /***********************************************************************
47  *           FILE_Alloc
48  *
49  * Allocate a file.
50  */
51 static HFILE32 FILE_Alloc( DOS_FILE **file )
52 {
53     HFILE32 handle;
54     *file = HeapAlloc( SystemHeap, 0, sizeof(DOS_FILE) );
55     if (!*file)
56     {
57         DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
58         return NULL;
59     }
60     (*file)->header.type = K32OBJ_FILE;
61     (*file)->header.refcount = 0;
62     (*file)->unix_handle = -1;
63     (*file)->unix_name = NULL;
64     (*file)->type = FILE_TYPE_DISK;
65
66     handle = PROCESS_AllocHandle( &(*file)->header, 0 );
67     if (handle == INVALID_HANDLE_VALUE32) *file = NULL;
68     return handle;
69 }
70
71
72 /***********************************************************************
73  *           FILE_Destroy
74  *
75  * Destroy a DOS file.
76  */
77 void FILE_Destroy( K32OBJ *ptr )
78 {
79     DOS_FILE *file = (DOS_FILE *)ptr;
80     assert( ptr->type == K32OBJ_FILE );
81
82     if (file->unix_handle != -1) close( file->unix_handle );
83     if (file->unix_name) HeapFree( SystemHeap, 0, file->unix_name );
84     ptr->type = K32OBJ_UNKNOWN;
85     HeapFree( SystemHeap, 0, file );
86 }
87
88
89 /***********************************************************************
90  *           FILE_GetFile
91  *
92  * Return the DOS file associated to a task file handle. FILE_ReleaseFile must
93  * be called to release the file.
94  */
95 static DOS_FILE *FILE_GetFile( HFILE32 handle )
96 {
97     return (DOS_FILE *)PROCESS_GetObjPtr( handle, K32OBJ_FILE );
98 }
99
100
101 /***********************************************************************
102  *           FILE_ReleaseFile
103  *
104  * Release a DOS file obtained with FILE_GetFile.
105  */
106 static void FILE_ReleaseFile( DOS_FILE *file )
107 {
108     K32OBJ_DecCount( &file->header );
109 }
110
111
112 /***********************************************************************
113  *           FILE_GetUnixHandle
114  *
115  * Return the Unix handle associated to a file handle.
116  */
117 int FILE_GetUnixHandle( HFILE32 hFile )
118 {
119     DOS_FILE *file;
120     int ret;
121
122     if (!(file = FILE_GetFile( hFile ))) return -1;
123     ret = file->unix_handle;
124     FILE_ReleaseFile( file );
125     return ret;
126 }
127
128
129 /***********************************************************************
130  *           FILE_SetDosError
131  *
132  * Set the DOS error code from errno.
133  */
134 void FILE_SetDosError(void)
135 {
136     dprintf_file(stddeb, "FILE_SetDosError: errno = %d\n", errno );
137     switch (errno)
138     {
139     case EAGAIN:
140         DOS_ERROR( ER_ShareViolation, EC_Temporary, SA_Retry, EL_Disk );
141         break;
142     case EBADF:
143         DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
144         break;
145     case ENOSPC:
146         DOS_ERROR( ER_DiskFull, EC_MediaError, SA_Abort, EL_Disk );
147         break;
148     case EACCES:
149     case EPERM:
150     case EROFS:
151         DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
152         break;
153     case EBUSY:
154         DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Abort, EL_Disk );
155         break;
156     case ENOENT:
157         DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
158         break;
159     case EISDIR:
160         DOS_ERROR( ER_CanNotMakeDir, EC_AccessDenied, SA_Abort, EL_Unknown );
161         break;
162     case ENFILE:
163     case EMFILE:
164         DOS_ERROR( ER_NoMoreFiles, EC_MediaError, SA_Abort, EL_Unknown );
165         break;
166     case EEXIST:
167         DOS_ERROR( ER_FileExists, EC_Exists, SA_Abort, EL_Disk );
168         break;
169     default:
170         perror( "int21: unknown errno" );
171         DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort, EL_Unknown );
172         break;
173     }
174 }
175
176
177 /***********************************************************************
178  *           FILE_DupUnixHandle
179  *
180  * Duplicate a Unix handle into a task handle.
181  */
182 HFILE32 FILE_DupUnixHandle( int fd )
183 {
184     HFILE32 handle;
185     DOS_FILE *file;
186
187     if ((handle = FILE_Alloc( &file )) != INVALID_HANDLE_VALUE32)
188     {
189         if ((file->unix_handle = dup(fd)) == -1)
190         {
191             FILE_SetDosError();
192             CloseHandle( handle );
193             return INVALID_HANDLE_VALUE32;
194         }
195     }
196     return handle;
197 }
198
199
200 /***********************************************************************
201  *           FILE_OpenUnixFile
202  */
203 static HFILE32 FILE_OpenUnixFile( const char *name, int mode )
204 {
205     HFILE32 handle;
206     DOS_FILE *file;
207     struct stat st;
208
209     if ((handle = FILE_Alloc( &file )) == INVALID_HANDLE_VALUE32)
210         return INVALID_HANDLE_VALUE32;
211
212     if ((file->unix_handle = open( name, mode, 0666 )) == -1)
213     {
214         if (!Options.failReadOnly && (mode == O_RDWR))
215             file->unix_handle = open( name, O_RDONLY );
216     }
217     if ((file->unix_handle == -1) || (fstat( file->unix_handle, &st ) == -1))
218     {
219         FILE_SetDosError();
220         CloseHandle( handle );
221         return INVALID_HANDLE_VALUE32;
222     }
223     if (S_ISDIR(st.st_mode))
224     {
225         DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
226         CloseHandle( handle );
227         return INVALID_HANDLE_VALUE32;
228     }
229
230     /* File opened OK, now fill the DOS_FILE */
231
232     file->unix_name = HEAP_strdupA( SystemHeap, 0, name );
233     return handle;
234 }
235
236
237 /***********************************************************************
238  *           FILE_Open
239  */
240 HFILE32 FILE_Open( LPCSTR path, INT32 mode )
241 {
242     DOS_FULL_NAME full_name;
243     const char *unixName;
244
245     dprintf_file(stddeb, "FILE_Open: '%s' %04x\n", path, mode );
246     if ((unixName = DOSFS_IsDevice( path )) != NULL)
247     {
248         dprintf_file( stddeb, "FILE_Open: opening device '%s'\n", unixName );
249         if (!unixName[0])  /* Non-existing device */
250         {
251             dprintf_file(stddeb, "FILE_Open: Non-existing device\n");
252             DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
253             return HFILE_ERROR32;
254         }
255     }
256     else /* check for filename, don't check for last entry if creating */
257     {
258         if (!DOSFS_GetFullName( path, !(mode & O_CREAT), &full_name ))
259             return HFILE_ERROR32;
260         unixName = full_name.long_name;
261     }
262     return FILE_OpenUnixFile( unixName, mode );
263 }
264
265
266 /***********************************************************************
267  *           FILE_Create
268  */
269 static HFILE32 FILE_Create( LPCSTR path, int mode, int unique )
270 {
271     HFILE32 handle;
272     DOS_FILE *file;
273     const char *unixName;
274     DOS_FULL_NAME full_name;
275
276     dprintf_file(stddeb, "FILE_Create: '%s' %04x %d\n", path, mode, unique );
277
278     if ((unixName = DOSFS_IsDevice( path )) != NULL)
279     {
280         dprintf_file(stddeb, "FILE_Create: creating device '%s'!\n", unixName);
281         DOS_ERROR( ER_AccessDenied, EC_NotFound, SA_Abort, EL_Disk );
282         return INVALID_HANDLE_VALUE32;
283     }
284
285     if ((handle = FILE_Alloc( &file )) == INVALID_HANDLE_VALUE32)
286         return INVALID_HANDLE_VALUE32;
287
288     if (!DOSFS_GetFullName( path, FALSE, &full_name ))
289     {
290         CloseHandle( handle );
291         return INVALID_HANDLE_VALUE32;
292     }
293     if ((file->unix_handle = open( full_name.long_name,
294                            O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
295                            mode )) == -1)
296     {
297         FILE_SetDosError();
298         CloseHandle( handle );
299         return INVALID_HANDLE_VALUE32;
300     } 
301
302     /* File created OK, now fill the DOS_FILE */
303
304     file->unix_name = HEAP_strdupA( SystemHeap, 0, full_name.long_name );
305     return handle;
306 }
307
308
309 /***********************************************************************
310  *           FILE_FillInfo
311  *
312  * Fill a file information from a struct stat.
313  */
314 static void FILE_FillInfo( struct stat *st, BY_HANDLE_FILE_INFORMATION *info )
315 {
316     info->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
317     if (S_ISDIR(st->st_mode))
318         info->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
319
320     DOSFS_UnixTimeToFileTime( st->st_mtime, &info->ftCreationTime, 0 );
321     DOSFS_UnixTimeToFileTime( st->st_mtime, &info->ftLastWriteTime, 0 );
322     DOSFS_UnixTimeToFileTime( st->st_atime, &info->ftLastAccessTime, 0 );
323
324     info->dwVolumeSerialNumber = 0;  /* FIXME */
325     info->nFileSizeHigh = 0;
326     info->nFileSizeLow  = S_ISDIR(st->st_mode) ? 0 : st->st_size;
327     info->nNumberOfLinks = st->st_nlink;
328     info->nFileIndexHigh = 0;
329     info->nFileIndexLow  = st->st_ino;
330 }
331
332
333 /***********************************************************************
334  *           FILE_Stat
335  *
336  * Stat a Unix path name. Return TRUE if OK.
337  */
338 BOOL32 FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info )
339 {
340     struct stat st;
341
342     if (stat( unixName, &st ) == -1)
343     {
344         FILE_SetDosError();
345         return FALSE;
346     }
347     FILE_FillInfo( &st, info );
348     return TRUE;
349 }
350
351
352 /***********************************************************************
353  *             GetFileInformationByHandle   (KERNEL32.219)
354  */
355 DWORD GetFileInformationByHandle( HFILE32 hFile,
356                                   BY_HANDLE_FILE_INFORMATION *info )
357 {
358     DOS_FILE *file;
359     DWORD ret = 0;
360     struct stat st;
361
362     if (!(file = FILE_GetFile( hFile ))) return 0;
363     if (fstat( file->unix_handle, &st ) == -1) FILE_SetDosError();
364     else
365     {
366         FILE_FillInfo( &st, info );
367         ret = 1;
368     }
369     FILE_ReleaseFile( file );
370     return ret;
371 }
372
373
374 /**************************************************************************
375  *           GetFileAttributes16   (KERNEL.420)
376  */
377 DWORD GetFileAttributes16( LPCSTR name )
378 {
379     return GetFileAttributes32A( name );
380 }
381
382
383 /**************************************************************************
384  *           GetFileAttributes32A   (KERNEL32.217)
385  */
386 DWORD GetFileAttributes32A( LPCSTR name )
387 {
388     DOS_FULL_NAME full_name;
389     BY_HANDLE_FILE_INFORMATION info;
390
391     if (!DOSFS_GetFullName( name, TRUE, &full_name )) return -1;
392     if (!FILE_Stat( full_name.long_name, &info )) return -1;
393     return info.dwFileAttributes;
394 }
395
396
397 /**************************************************************************
398  *           GetFileAttributes32W   (KERNEL32.218)
399  */
400 DWORD GetFileAttributes32W( LPCWSTR name )
401 {
402     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
403     DWORD res = GetFileAttributes32A( nameA );
404     HeapFree( GetProcessHeap(), 0, nameA );
405     return res;
406 }
407
408
409 /***********************************************************************
410  *           GetFileSize   (KERNEL32.220)
411  */
412 DWORD GetFileSize( HFILE32 hFile, LPDWORD filesizehigh )
413 {
414     BY_HANDLE_FILE_INFORMATION info;
415     if (!GetFileInformationByHandle( hFile, &info )) return 0;
416     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
417     return info.nFileSizeLow;
418 }
419
420
421 /***********************************************************************
422  *           GetFileTime   (KERNEL32.221)
423  */
424 BOOL32 GetFileTime( HFILE32 hFile, FILETIME *lpCreationTime,
425                     FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime )
426 {
427     BY_HANDLE_FILE_INFORMATION info;
428     if (!GetFileInformationByHandle( hFile, &info )) return FALSE;
429     if (lpCreationTime)   *lpCreationTime   = info.ftCreationTime;
430     if (lpLastAccessTime) *lpLastAccessTime = info.ftLastAccessTime;
431     if (lpLastWriteTime)  *lpLastWriteTime  = info.ftLastWriteTime;
432     return TRUE;
433 }
434
435
436 /***********************************************************************
437  *           FILE_Dup
438  *
439  * dup() function for DOS handles.
440  */
441 HFILE32 FILE_Dup( HFILE32 hFile )
442 {
443     DOS_FILE *file;
444     HFILE32 handle;
445
446     dprintf_file( stddeb, "FILE_Dup for handle %d\n", hFile );
447     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR32;
448     handle = PROCESS_AllocHandle( &file->header, 0 );
449     FILE_ReleaseFile( file );
450     dprintf_file( stddeb, "FILE_Dup return handle %d\n", handle );
451     return handle;
452 }
453
454
455 /***********************************************************************
456  *           FILE_Dup2
457  *
458  * dup2() function for DOS handles.
459  */
460 HFILE32 FILE_Dup2( HFILE32 hFile1, HFILE32 hFile2 )
461 {
462     DOS_FILE *file;
463
464     dprintf_file( stddeb, "FILE_Dup2 for handle %d\n", hFile1 );
465     if (!(file = FILE_GetFile( hFile1 ))) return HFILE_ERROR32;
466     if (!PROCESS_SetObjPtr( hFile2, &file->header, 0 )) hFile2 = HFILE_ERROR32;
467     FILE_ReleaseFile( file );
468     return hFile2;
469 }
470
471
472 /***********************************************************************
473  *           GetTempFileName16   (KERNEL.97)
474  */
475 UINT16 GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
476                           LPSTR buffer )
477 {
478     char temppath[144];
479
480     if ((drive & TF_FORCEDRIVE) &&
481         !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
482     {
483         drive &= ~TF_FORCEDRIVE;
484         fprintf( stderr, "Warning: GetTempFileName: invalid drive %d specified\n",
485                  drive );
486     }
487
488     if (drive & TF_FORCEDRIVE)
489         sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
490     else
491     {
492         GetTempPath32A( 132, temppath );
493         strcat( temppath, "\\" );
494     }
495     return (UINT16)GetTempFileName32A( temppath, prefix, unique, buffer );
496 }
497
498
499 /***********************************************************************
500  *           GetTempFileName32A   (KERNEL32.290)
501  */
502 UINT32 GetTempFileName32A( LPCSTR path, LPCSTR prefix, UINT32 unique,
503                            LPSTR buffer)
504 {
505     DOS_FULL_NAME full_name;
506     int i;
507     LPSTR p;
508     UINT32 num = unique ? (unique & 0xffff) : time(NULL) & 0xffff;
509
510     if (!path) return 0;
511     strcpy( buffer, path );
512     p = buffer + strlen(buffer);
513     *p++ = '~';
514     for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
515     sprintf( p, "%04x.tmp", num );
516
517     /* Now try to create it */
518
519     if (!unique)
520     {
521         do
522         {
523             HFILE32 handle = FILE_Create( buffer, 0666, TRUE );
524             if (handle != INVALID_HANDLE_VALUE32)
525             {  /* We created it */
526                 dprintf_file( stddeb, "GetTempFileName: created %s\n", buffer);
527                 CloseHandle( handle );
528                 break;
529             }
530             if (DOS_ExtendedError != ER_FileExists)
531                 break;  /* No need to go on */
532             num++;
533             sprintf( p, "%04x.tmp", num );
534         } while (num != (unique & 0xffff));
535     }
536
537     /* Get the full path name */
538
539     if (DOSFS_GetFullName( buffer, FALSE, &full_name ))
540     {
541         if (access( full_name.long_name, W_OK ) == -1)
542             fprintf( stderr,
543                      "Warning: GetTempFileName returns '%s', which doesn't seem to be writeable.\n"
544                      "Please check your configuration file if this generates a failure.\n",
545                      buffer);
546     }
547     dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
548     return unique ? unique : num;
549 }
550
551
552 /***********************************************************************
553  *           GetTempFileName32W   (KERNEL32.291)
554  */
555 UINT32 GetTempFileName32W( LPCWSTR path, LPCWSTR prefix, UINT32 unique,
556                            LPWSTR buffer )
557 {
558     LPSTR   patha,prefixa;
559     char    buffera[144];
560     UINT32  ret;
561
562     if (!path) return 0;
563     patha   = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
564     prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
565     ret     = GetTempFileName32A( patha, prefixa, unique, buffera );
566     lstrcpyAtoW( buffer, buffera );
567     HeapFree( GetProcessHeap(), 0, patha );
568     HeapFree( GetProcessHeap(), 0, prefixa );
569     return ret;
570 }
571
572
573 /***********************************************************************
574  *           FILE_DoOpenFile
575  *
576  * Implementation of OpenFile16() and OpenFile32().
577  */
578 static HFILE32 FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT32 mode,
579                                 BOOL32 win32 )
580 {
581     HFILE32 hFileRet;
582     FILETIME filetime;
583     WORD filedatetime[2];
584     DOS_FULL_NAME full_name;
585     char *p;
586     int unixMode;
587
588     ofs->cBytes = sizeof(OFSTRUCT);
589     ofs->nErrCode = 0;
590     if (mode & OF_REOPEN) name = ofs->szPathName;
591     dprintf_file( stddeb, "OpenFile: %s %04x\n", name, mode );
592
593     /* OF_PARSE simply fills the structure */
594
595     if (mode & OF_PARSE)
596     {
597         if (!GetFullPathName32A( name, sizeof(ofs->szPathName),
598                                  ofs->szPathName, NULL )) goto error;
599         ofs->fFixedDisk = (GetDriveType16( ofs->szPathName[0]-'A' )
600                            != DRIVE_REMOVABLE);
601         dprintf_file( stddeb, "OpenFile(%s): OF_PARSE, res = '%s'\n",
602                       name, ofs->szPathName );
603         return 0;
604     }
605
606     /* OF_CREATE is completely different from all other options, so
607        handle it first */
608
609     if (mode & OF_CREATE)
610     {
611         if ((hFileRet = FILE_Create(name,0666,FALSE))== INVALID_HANDLE_VALUE32)
612             goto error;
613         GetFullPathName32A( name, sizeof(ofs->szPathName),
614                             ofs->szPathName, NULL );
615         goto success;
616     }
617
618     /* If OF_SEARCH is set, ignore the given path */
619
620     if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
621     {
622         /* First try the file name as is */
623         if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found;
624         /* Now remove the path */
625         if (name[0] && (name[1] == ':')) name += 2;
626         if ((p = strrchr( name, '\\' ))) name = p + 1;
627         if ((p = strrchr( name, '/' ))) name = p + 1;
628         if (!name[0]) goto not_found;
629     }
630
631     /* Now look for the file */
632
633     if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found;
634
635 found:
636     dprintf_file( stddeb, "OpenFile: found %s = %s\n",
637                   full_name.long_name, full_name.short_name );
638     lstrcpyn32A( ofs->szPathName, full_name.short_name,
639                  sizeof(ofs->szPathName) );
640
641     if (mode & OF_DELETE)
642     {
643         if (unlink( full_name.long_name ) == -1) goto not_found;
644         dprintf_file( stddeb, "OpenFile(%s): OF_DELETE return = OK\n", name);
645         return 1;
646     }
647
648     switch(mode & 3)
649     {
650     case OF_WRITE:
651         unixMode = O_WRONLY; break;
652     case OF_READWRITE:
653         unixMode = O_RDWR; break;
654     case OF_READ:
655     default:
656         unixMode = O_RDONLY; break;
657     }
658
659     hFileRet = FILE_OpenUnixFile( full_name.long_name, unixMode );
660     if (hFileRet == HFILE_ERROR32) goto not_found;
661     GetFileTime( hFileRet, NULL, NULL, &filetime );
662     FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
663     if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
664     {
665         if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
666         {
667             CloseHandle( hFileRet );
668             dprintf_file( stddeb, "OpenFile(%s): OF_VERIFY failed\n", name );
669             /* FIXME: what error here? */
670             DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
671             goto error;
672         }
673     }
674     memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
675
676 success:  /* We get here if the open was successful */
677     dprintf_file( stddeb, "OpenFile(%s): OK, return = %d\n", name, hFileRet );
678     if (mode & OF_EXIST) /* Return the handle, but close it first */
679         CloseHandle( hFileRet );
680     return hFileRet;
681
682 not_found:  /* We get here if the file does not exist */
683     dprintf_file( stddeb, "OpenFile: '%s' not found\n", name );
684     DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
685     /* fall through */
686
687 error:  /* We get here if there was an error opening the file */
688     ofs->nErrCode = DOS_ExtendedError;
689     dprintf_file( stddeb, "OpenFile(%s): return = HFILE_ERROR\n", name );
690     return HFILE_ERROR32;
691 }
692
693
694 /***********************************************************************
695  *           OpenFile16   (KERNEL.74)
696  */
697 HFILE16 OpenFile16( LPCSTR name, OFSTRUCT *ofs, UINT16 mode )
698 {
699     return FILE_DoOpenFile( name, ofs, mode, FALSE );
700 }
701
702
703 /***********************************************************************
704  *           OpenFile32   (KERNEL32.396)
705  */
706 HFILE32 OpenFile32( LPCSTR name, OFSTRUCT *ofs, UINT32 mode )
707 {
708     return FILE_DoOpenFile( name, ofs, mode, TRUE );
709 }
710
711
712 /***********************************************************************
713  *           _lclose16   (KERNEL.81)
714  */
715 HFILE16 _lclose16( HFILE16 hFile )
716 {
717     dprintf_file( stddeb, "_lclose16: handle %d\n", hFile );
718     return CloseHandle( hFile ) ? 0 : HFILE_ERROR16;
719 }
720
721
722 /***********************************************************************
723  *           _lclose32   (KERNEL32.592)
724  */
725 HFILE32 _lclose32( HFILE32 hFile )
726 {
727     dprintf_file( stddeb, "_lclose32: handle %d\n", hFile );
728     return CloseHandle( hFile ) ? 0 : HFILE_ERROR32;
729 }
730
731
732 /***********************************************************************
733  *           WIN16_hread
734  */
735 LONG WIN16_hread( HFILE16 hFile, SEGPTR buffer, LONG count )
736 {
737     LONG maxlen;
738
739     dprintf_file( stddeb, "_hread16: %d %08lx %ld\n",
740                   hFile, (DWORD)buffer, count );
741
742     /* Some programs pass a count larger than the allocated buffer */
743     maxlen = GetSelectorLimit( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
744     if (count > maxlen) count = maxlen;
745     return _lread32( hFile, PTR_SEG_TO_LIN(buffer), count );
746 }
747
748
749 /***********************************************************************
750  *           WIN16_lread
751  */
752 UINT16 WIN16_lread( HFILE16 hFile, SEGPTR buffer, UINT16 count )
753 {
754     return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
755 }
756
757
758 /***********************************************************************
759  *           _lread32   (KERNEL32.596)
760  */
761 UINT32 _lread32( HFILE32 hFile, LPVOID buffer, UINT32 count )
762 {
763     DOS_FILE *file;
764     UINT32 result;
765
766     dprintf_file( stddeb, "_lread32: %d %p %d\n", hFile, buffer, count );
767     if (!(file = FILE_GetFile( hFile ))) return -1;
768     if (!count) result = 0;
769     else if ((result = read( file->unix_handle, buffer, count )) == -1)
770         FILE_SetDosError();
771     FILE_ReleaseFile( file );
772     return result;
773 }
774
775
776 /***********************************************************************
777  *           _lread16   (KERNEL.82)
778  */
779 UINT16 _lread16( HFILE16 hFile, LPVOID buffer, UINT16 count )
780 {
781     return (UINT16)_lread32( hFile, buffer, (LONG)count );
782 }
783
784
785 /***********************************************************************
786  *           _lcreat16   (KERNEL.83)
787  */
788 HFILE16 _lcreat16( LPCSTR path, INT16 attr )
789 {
790     int mode = (attr & 1) ? 0444 : 0666;
791     dprintf_file( stddeb, "_lcreat16: %s %02x\n", path, attr );
792     return (HFILE16)FILE_Create( path, mode, FALSE );
793 }
794
795
796 /***********************************************************************
797  *           _lcreat32   (KERNEL32.593)
798  */
799 HFILE32 _lcreat32( LPCSTR path, INT32 attr )
800 {
801     int mode = (attr & 1) ? 0444 : 0666;
802     dprintf_file( stddeb, "_lcreat32: %s %02x\n", path, attr );
803     return FILE_Create( path, mode, FALSE );
804 }
805
806
807 /***********************************************************************
808  *           _lcreat_uniq   (Not a Windows API)
809  */
810 HFILE32 _lcreat_uniq( LPCSTR path, INT32 attr )
811 {
812     int mode = (attr & 1) ? 0444 : 0666;
813     dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
814     return FILE_Create( path, mode, TRUE );
815 }
816
817
818 /***********************************************************************
819  *           SetFilePointer   (KERNEL32.492)
820  */
821 DWORD SetFilePointer( HFILE32 hFile, LONG distance, LONG *highword,
822                       DWORD method )
823 {
824     DOS_FILE *file;
825     int origin, result;
826
827     if (highword && *highword)
828     {
829         fprintf( stderr, "SetFilePointer: 64-bit offsets not supported yet\n");
830         SetLastError( ERROR_INVALID_PARAMETER );
831         return 0xffffffff;
832     }
833     dprintf_file( stddeb, "SetFilePointer: handle %d offset %ld origin %ld\n",
834                   hFile, distance, method );
835
836     if (!(file = FILE_GetFile( hFile ))) return 0xffffffff;
837     switch(method)
838     {
839         case 1:  origin = SEEK_CUR; break;
840         case 2:  origin = SEEK_END; break;
841         default: origin = SEEK_SET; break;
842     }
843
844     if ((result = lseek( file->unix_handle, distance, origin )) == -1)
845         FILE_SetDosError();
846     FILE_ReleaseFile( file );
847     return (DWORD)result;
848 }
849
850
851 /***********************************************************************
852  *           _llseek16   (KERNEL.84)
853  */
854 LONG _llseek16( HFILE16 hFile, LONG lOffset, INT16 nOrigin )
855 {
856     return SetFilePointer( hFile, lOffset, NULL, nOrigin );
857 }
858
859
860 /***********************************************************************
861  *           _llseek32   (KERNEL32.594)
862  */
863 LONG _llseek32( HFILE32 hFile, LONG lOffset, INT32 nOrigin )
864 {
865     return SetFilePointer( hFile, lOffset, NULL, nOrigin );
866 }
867
868
869 /***********************************************************************
870  *           _lopen16   (KERNEL.85)
871  */
872 HFILE16 _lopen16( LPCSTR path, INT16 mode )
873 {
874     return _lopen32( path, mode );
875 }
876
877
878 /***********************************************************************
879  *           _lopen32   (KERNEL32.595)
880  */
881 HFILE32 _lopen32( LPCSTR path, INT32 mode )
882 {
883     INT32 unixMode;
884
885     dprintf_file(stddeb, "_lopen('%s',%04x)\n", path, mode );
886
887     switch(mode & 3)
888     {
889     case OF_WRITE:
890         unixMode = O_WRONLY | O_TRUNC;
891         break;
892     case OF_READWRITE:
893         unixMode = O_RDWR;
894         break;
895     case OF_READ:
896     default:
897         unixMode = O_RDONLY;
898         break;
899     }
900     return FILE_Open( path, unixMode );
901 }
902
903
904 /***********************************************************************
905  *           _lwrite16   (KERNEL.86)
906  */
907 UINT16 _lwrite16( HFILE16 hFile, LPCSTR buffer, UINT16 count )
908 {
909     return (UINT16)_hwrite32( hFile, buffer, (LONG)count );
910 }
911
912 /***********************************************************************
913  *           _lwrite32   (KERNEL.86)
914  */
915 UINT32 _lwrite32( HFILE32 hFile, LPCSTR buffer, UINT32 count )
916 {
917     return (UINT32)_hwrite32( hFile, buffer, (LONG)count );
918 }
919
920
921 /***********************************************************************
922  *           _hread16   (KERNEL.349)
923  */
924 LONG _hread16( HFILE16 hFile, LPVOID buffer, LONG count)
925 {
926     return _lread32( hFile, buffer, count );
927 }
928
929
930 /***********************************************************************
931  *           _hread32   (KERNEL32.590)
932  */
933 LONG _hread32( HFILE32 hFile, LPVOID buffer, LONG count)
934 {
935     return _lread32( hFile, buffer, count );
936 }
937
938
939 /***********************************************************************
940  *           _hwrite16   (KERNEL.350)
941  */
942 LONG _hwrite16( HFILE16 hFile, LPCSTR buffer, LONG count )
943 {
944     return _hwrite32( hFile, buffer, count );
945 }
946
947
948 /***********************************************************************
949  *           _hwrite32   (KERNEL32.591)
950  */
951 LONG _hwrite32( HFILE32 hFile, LPCSTR buffer, LONG count )
952 {
953     DOS_FILE *file;
954     LONG result;
955
956     dprintf_file( stddeb, "_hwrite: %d %p %ld\n", hFile, buffer, count );
957
958     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR32;
959     if (count == 0)  /* Expand or truncate at current position */
960         result = ftruncate( file->unix_handle,
961                             lseek( file->unix_handle, 0, SEEK_CUR ) );
962     else
963         result = write( file->unix_handle, buffer, count );
964
965     if (result == -1) FILE_SetDosError();
966     FILE_ReleaseFile( file );
967     return result;
968 }
969
970
971 /***********************************************************************
972  *           SetHandleCount16   (KERNEL.199)
973  */
974 UINT16 SetHandleCount16( UINT16 count )
975 {
976     HGLOBAL16 hPDB = GetCurrentPDB();
977     PDB *pdb = (PDB *)GlobalLock16( hPDB );
978     BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
979
980     dprintf_file( stddeb, "SetHandleCount(%d)\n", count );
981
982     if (count < 20) count = 20;  /* No point in going below 20 */
983     else if (count > 254) count = 254;
984
985     if (count == 20)
986     {
987         if (pdb->nbFiles > 20)
988         {
989             memcpy( pdb->fileHandles, files, 20 );
990             GlobalFree16( pdb->hFileHandles );
991             pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
992                                                    GlobalHandleToSel( hPDB ) );
993             pdb->hFileHandles = 0;
994             pdb->nbFiles = 20;
995         }
996     }
997     else  /* More than 20, need a new file handles table */
998     {
999         BYTE *newfiles;
1000         HGLOBAL16 newhandle = GlobalAlloc16( GMEM_MOVEABLE, count );
1001         if (!newhandle)
1002         {
1003             DOS_ERROR( ER_OutOfMemory, EC_OutOfResource, SA_Abort, EL_Memory );
1004             return pdb->nbFiles;
1005         }
1006         newfiles = (BYTE *)GlobalLock16( newhandle );
1007
1008         if (count > pdb->nbFiles)
1009         {
1010             memcpy( newfiles, files, pdb->nbFiles );
1011             memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1012         }
1013         else memcpy( newfiles, files, count );
1014         if (pdb->nbFiles > 20) GlobalFree16( pdb->hFileHandles );
1015         pdb->fileHandlesPtr = WIN16_GlobalLock16( newhandle );
1016         pdb->hFileHandles   = newhandle;
1017         pdb->nbFiles = count;
1018     }
1019     return pdb->nbFiles;
1020 }
1021
1022
1023 /*************************************************************************
1024  *           SetHandleCount32   (KERNEL32.494)
1025  */
1026 UINT32 SetHandleCount32( UINT32 count )
1027 {
1028     return MIN( 256, count );
1029 }
1030
1031
1032 /***********************************************************************
1033  *           FlushFileBuffers   (KERNEL32.133)
1034  */
1035 BOOL32 FlushFileBuffers( HFILE32 hFile )
1036 {
1037     DOS_FILE *file;
1038     BOOL32 ret;
1039
1040     dprintf_file( stddeb, "FlushFileBuffers(%d)\n", hFile );
1041     if (!(file = FILE_GetFile( hFile ))) return FALSE;
1042     if (fsync( file->unix_handle ) != -1) ret = TRUE;
1043     else
1044     {
1045         FILE_SetDosError();
1046         ret = FALSE;
1047     }
1048     FILE_ReleaseFile( file );
1049     return ret;
1050 }
1051
1052
1053 /**************************************************************************
1054  *           SetEndOfFile   (KERNEL32.483)
1055  */
1056 BOOL32 SetEndOfFile( HFILE32 hFile )
1057 {
1058     DOS_FILE *file;
1059     BOOL32 ret = TRUE;
1060
1061     dprintf_file( stddeb, "SetEndOfFile(%d)\n", hFile );
1062     if (!(file = FILE_GetFile( hFile ))) return FALSE;
1063     if (ftruncate( file->unix_handle,
1064                    lseek( file->unix_handle, 0, SEEK_CUR ) ))
1065     {
1066         FILE_SetDosError();
1067         ret = FALSE;
1068     }
1069     FILE_ReleaseFile( file );
1070     return ret;
1071 }
1072
1073
1074 /***********************************************************************
1075  *           DeleteFile16   (KERNEL.146)
1076  */
1077 BOOL16 DeleteFile16( LPCSTR path )
1078 {
1079     return DeleteFile32A( path );
1080 }
1081
1082
1083 /***********************************************************************
1084  *           DeleteFile32A   (KERNEL32.71)
1085  */
1086 BOOL32 DeleteFile32A( LPCSTR path )
1087 {
1088     DOS_FULL_NAME full_name;
1089     const char *unixName;
1090
1091     dprintf_file(stddeb, "DeleteFile: '%s'\n", path );
1092
1093     if ((unixName = DOSFS_IsDevice( path )) != NULL)
1094     {
1095         dprintf_file(stddeb, "DeleteFile: removing device '%s'!\n", unixName);
1096         DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
1097         return FALSE;
1098     }
1099
1100     if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
1101     if (unlink( full_name.long_name ) == -1)
1102     {
1103         FILE_SetDosError();
1104         return FALSE;
1105     }
1106     return TRUE;
1107 }
1108
1109
1110 /***********************************************************************
1111  *           DeleteFile32W   (KERNEL32.72)
1112  */
1113 BOOL32 DeleteFile32W( LPCWSTR path )
1114 {
1115     LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1116     BOOL32 ret = RemoveDirectory32A( xpath );
1117     HeapFree( GetProcessHeap(), 0, xpath );
1118     return ret;
1119 }
1120
1121
1122 /***********************************************************************
1123  *           FILE_SetFileType
1124  */
1125 BOOL32 FILE_SetFileType( HFILE32 hFile, DWORD type )
1126 {
1127     DOS_FILE *file = FILE_GetFile( hFile );
1128     if (!file) return FALSE;
1129     file->type = type;
1130     FILE_ReleaseFile( file );
1131     return TRUE;
1132 }
1133
1134
1135 /***********************************************************************
1136  *           GetFileType   (KERNEL32.222)
1137  */
1138 DWORD GetFileType( HFILE32 hFile )
1139 {
1140     DOS_FILE *file = FILE_GetFile(hFile);
1141     if (!file) return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1142     FILE_ReleaseFile( file );
1143     return file->type;
1144 }
1145
1146
1147 /**************************************************************************
1148  *           MoveFile32A   (KERNEL32.387)
1149  */
1150 BOOL32 MoveFile32A( LPCSTR fn1, LPCSTR fn2 )
1151 {
1152     DOS_FULL_NAME full_name1, full_name2;
1153
1154     dprintf_file( stddeb, "MoveFile32A(%s,%s)\n", fn1, fn2 );
1155
1156     if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
1157     if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
1158     /* FIXME: should not replace an existing file */
1159     /* FIXME: should handle renaming across devices */
1160     if (rename( full_name1.long_name, full_name2.long_name ) == -1)
1161     {
1162         FILE_SetDosError();
1163         return FALSE;
1164     }
1165     return TRUE;
1166 }
1167
1168
1169 /**************************************************************************
1170  *           MoveFile32W   (KERNEL32.390)
1171  */
1172 BOOL32 MoveFile32W( LPCWSTR fn1, LPCWSTR fn2 )
1173 {
1174     LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
1175     LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
1176     BOOL32 res = MoveFile32A( afn1, afn2 );
1177     HeapFree( GetProcessHeap(), 0, afn1 );
1178     HeapFree( GetProcessHeap(), 0, afn2 );
1179     return res;
1180 }
1181
1182
1183 /**************************************************************************
1184  *           CopyFile32A   (KERNEL32.36)
1185  */
1186 BOOL32 CopyFile32A( LPCSTR source, LPCSTR dest, BOOL32 fail_if_exists )
1187 {
1188     HFILE32 h1, h2;
1189     BY_HANDLE_FILE_INFORMATION info;
1190     UINT32 count;
1191     BOOL32 ret = FALSE;
1192     int mode;
1193     char buffer[2048];
1194
1195     if ((h1 = _lopen32( source, OF_READ )) == HFILE_ERROR32) return FALSE;
1196     if (!GetFileInformationByHandle( h1, &info ))
1197     {
1198         CloseHandle( h1 );
1199         return FALSE;
1200     }
1201     mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
1202     if ((h2 = FILE_Create( dest, mode, fail_if_exists )) == HFILE_ERROR32)
1203     {
1204         CloseHandle( h1 );
1205         return FALSE;
1206     }
1207     while ((count = _lread32( h2, buffer, sizeof(buffer) )) > 0)
1208     {
1209         char *p = buffer;
1210         while (count > 0)
1211         {
1212             INT32 res = _lwrite32( h2, p, count );
1213             if (res <= 0) goto done;
1214             p += res;
1215             count -= res;
1216         }
1217     }
1218     ret =  TRUE;
1219 done:
1220     CloseHandle( h1 );
1221     CloseHandle( h2 );
1222     return ret;
1223 }
1224
1225
1226 /**************************************************************************
1227  *           CopyFile32W   (KERNEL32.37)
1228  */
1229 BOOL32 CopyFile32W( LPCWSTR source, LPCWSTR dest, BOOL32 fail_if_exists )
1230 {
1231     LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source );
1232     LPSTR destA   = HEAP_strdupWtoA( GetProcessHeap(), 0, dest );
1233     BOOL32 ret = CopyFile32A( sourceA, destA, fail_if_exists );
1234     HeapFree( GetProcessHeap(), 0, sourceA );
1235     HeapFree( GetProcessHeap(), 0, destA );
1236     return ret;
1237 }
1238
1239
1240 /***********************************************************************
1241  *              SetFileTime   (KERNEL32.493)
1242  */
1243 BOOL32 SetFileTime( HFILE32 hFile,
1244                     const FILETIME *lpCreationTime,
1245                     const FILETIME *lpLastAccessTime,
1246                     const FILETIME *lpLastWriteTime )
1247 {
1248     DOS_FILE *file = FILE_GetFile(hFile);
1249     struct utimbuf utimbuf;
1250     
1251     if (!file) return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1252     dprintf_file(stddeb,"SetFileTime(%s,%p,%p,%p)\n",
1253         file->unix_name,
1254         lpCreationTime,
1255         lpLastAccessTime,
1256         lpLastWriteTime
1257     );
1258     if (lpLastAccessTime)
1259         utimbuf.actime  = DOSFS_FileTimeToUnixTime(lpLastAccessTime, NULL);
1260     else
1261         utimbuf.actime  = 0; /* FIXME */
1262     if (lpLastWriteTime)
1263         utimbuf.modtime = DOSFS_FileTimeToUnixTime(lpLastWriteTime, NULL);
1264     else
1265         utimbuf.modtime = 0; /* FIXME */
1266     if (-1==utime(file->unix_name,&utimbuf))
1267     {
1268         FILE_ReleaseFile( file );
1269         FILE_SetDosError();
1270         return FALSE;
1271     }
1272     FILE_ReleaseFile( file );
1273     return TRUE;
1274 }