Release 961215
[wine] / files / file.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 John Burton
5  * Copyright 1996 Alexandre Julliard
6  */
7
8 #include <ctype.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/errno.h>
15 #include <sys/stat.h>
16 #include <time.h>
17 #include <unistd.h>
18 #include <utime.h>
19
20 #include "windows.h"
21 #include "winerror.h"
22 #include "directory.h"
23 #include "dos_fs.h"
24 #include "drive.h"
25 #include "global.h"
26 #include "msdos.h"
27 #include "options.h"
28 #include "ldt.h"
29 #include "task.h"
30 #include "string32.h"
31 #include "stddebug.h"
32 #include "debug.h"
33 #include "xmalloc.h"
34
35 #define MAX_OPEN_FILES 64  /* Max. open files for all tasks; must be <255 */
36
37 typedef struct tagDOS_FILE
38 {
39     struct tagDOS_FILE *next;
40     int                 count;        /* Usage count (0 if free) */
41     int                 unix_handle;
42     int                 mode;
43     char               *unix_name;
44     WORD                filedate;
45     WORD                filetime;
46     DWORD               type;         /* Type for win32 apps */
47 } DOS_FILE;
48
49 /* Global files array */
50 static DOS_FILE DOSFiles[MAX_OPEN_FILES];
51
52 static DOS_FILE *FILE_First = DOSFiles;
53 static DOS_FILE *FILE_LastUsed = DOSFiles;
54
55 /* Small file handles array for boot-up, before the first PDB is created */
56 #define MAX_BOOT_HANDLES  4
57 static BYTE bootFileHandles[MAX_BOOT_HANDLES] = { 0xff, 0xff, 0xff, 0xff };
58
59 /***********************************************************************
60  *           FILE_Alloc
61  *
62  * Allocate a DOS file.
63  */
64 static DOS_FILE *FILE_Alloc(void)
65 {
66     DOS_FILE *file = FILE_First;
67     if (file) FILE_First = file->next;
68     else if (FILE_LastUsed >= &DOSFiles[MAX_OPEN_FILES-1])
69     {
70         DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
71         return NULL;
72     }
73     else file = ++FILE_LastUsed;
74     file->count = 1;
75     file->unix_handle = -1;
76     file->unix_name = NULL;
77     file->type = FILE_TYPE_DISK;
78     return file;
79 }
80
81
82 /***********************************************************************
83  *           FILE_Close
84  *
85  * Close a DOS file.
86  */
87 static BOOL FILE_Close( DOS_FILE *file )
88 {
89     if (!file->count) return FALSE;
90     if (--file->count > 0) return TRUE;
91     /* Now really close the file */
92     if (file->unix_handle != -1) close( file->unix_handle );
93     if (file->unix_name) free( file->unix_name );
94     file->next = FILE_First;
95     FILE_First = file;
96     return TRUE;
97 }
98
99
100 /***********************************************************************
101  *           FILE_GetPDBFiles
102  *
103  * Return a pointer to the current PDB files array.
104  */
105 static void FILE_GetPDBFiles( BYTE **files, WORD *nbFiles )
106 {
107     PDB *pdb;
108
109     if ((pdb = (PDB *)GlobalLock16( GetCurrentPDB() )) != NULL)
110     {
111         *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
112         *nbFiles = pdb->nbFiles;
113     }
114     else
115     {
116         *files = bootFileHandles;
117         *nbFiles = MAX_BOOT_HANDLES;
118     }
119 }
120
121
122 /***********************************************************************
123  *           FILE_AllocTaskHandle
124  *
125  * Allocate a task file handle for a DOS file.
126  */
127 static HFILE FILE_AllocTaskHandle( DOS_FILE *dos_file )
128 {
129     BYTE *files, *fp;
130     WORD i, nbFiles;
131
132     FILE_GetPDBFiles( &files, &nbFiles );
133     fp = files + 1;  /* Don't use handle 0, as some programs don't like it */
134     for (i = nbFiles - 1; (i > 0) && (*fp != 0xff); i--, fp++);
135     if (!i)
136     {  /* No more handles or files */
137         DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
138         return -1;
139     }
140     *fp = dos_file ? (BYTE)(dos_file - DOSFiles) : 0;
141     dprintf_file(stddeb, 
142        "FILE_AllocTaskHandle: returning task handle %d, dos_file %d, file %d of %d \n", 
143              (fp - files), *fp, nbFiles - i, nbFiles  );
144     return (HFILE)(fp - files);
145 }
146
147
148 /***********************************************************************
149  *           FILE_FreeTaskHandle
150  *
151  * Free a per-task file handle.
152  */
153 static void FILE_FreeTaskHandle( HFILE handle )
154 {
155     BYTE *files;
156     WORD nbFiles;
157
158     FILE_GetPDBFiles( &files, &nbFiles );
159     dprintf_file( stddeb,"FILE_FreeTaskHandle: dos=%d file=%d\n",
160                   handle, files[handle] );
161     if ((handle < 0) || (handle >= (INT)nbFiles))
162     {
163         fprintf( stderr, "FILE_FreeTaskHandle: invalid file handle %d\n",
164                  handle );
165         return;
166     }
167     files[handle] = 0xff;
168 }
169
170
171 /***********************************************************************
172  *           FILE_SetTaskHandle
173  *
174  * Set the value of a task handle (no error checking).
175  */
176 static void FILE_SetTaskHandle( HFILE handle, DOS_FILE *file )
177 {
178     BYTE *files;
179     WORD nbFiles;
180
181     FILE_GetPDBFiles( &files, &nbFiles );
182     files[handle] = (BYTE)(file - DOSFiles);
183 }
184
185
186 /***********************************************************************
187  *           FILE_GetFile
188  *
189  * Return the DOS file associated to a task file handle.
190  */
191 static DOS_FILE *FILE_GetFile( HFILE handle )
192 {
193     BYTE *files;
194     WORD nbFiles;
195     DOS_FILE *file;
196
197     FILE_GetPDBFiles( &files, &nbFiles );
198     if ((handle < 0) || (handle >= (INT)nbFiles) ||
199         (files[handle] >= MAX_OPEN_FILES) ||
200         !(file = &DOSFiles[files[handle]])->count)
201     {
202         DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
203         return NULL;
204     }
205     return file;
206 }
207
208
209 int FILE_GetUnixHandle( HFILE hFile )
210 {
211     DOS_FILE *file;
212
213     if (!(file = FILE_GetFile( hFile ))) return -1;
214     return file->unix_handle;
215 }
216
217
218 /***********************************************************************
219  *           FILE_CloseAllFiles
220  *
221  * Close all open files of a given PDB. Used on task termination.
222  */
223 void FILE_CloseAllFiles( HANDLE16 hPDB )
224 {
225     BYTE *files;
226     WORD count;
227     PDB *pdb = (PDB *)GlobalLock16( hPDB );
228
229     if (!pdb) return;
230     files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
231     dprintf_file(stddeb,"FILE_CloseAllFiles: closing %d files\n",pdb->nbFiles);
232     for (count = pdb->nbFiles; count > 0; count--, files++)
233     {
234         if (*files < MAX_OPEN_FILES) FILE_Close( &DOSFiles[*files] );
235         *files = 0xff;
236     }
237 }
238
239
240 /***********************************************************************
241  *           FILE_SetDosError
242  *
243  * Set the DOS error code from errno.
244  */
245 void FILE_SetDosError(void)
246 {
247     dprintf_file(stddeb, "FILE_SetDosError: errno = %d\n", errno );
248     switch (errno)
249     {
250     case EAGAIN:
251         DOS_ERROR( ER_ShareViolation, EC_Temporary, SA_Retry, EL_Disk );
252         break;
253     case EBADF:
254         DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
255         break;
256     case ENOSPC:
257         DOS_ERROR( ER_DiskFull, EC_MediaError, SA_Abort, EL_Disk );
258         break;
259     case EACCES:
260     case EPERM:
261     case EROFS:
262         DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
263         break;
264     case EBUSY:
265         DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Abort, EL_Disk );
266         break;
267     case ENOENT:
268         DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
269         break;
270     case EISDIR:
271         DOS_ERROR( ER_CanNotMakeDir, EC_AccessDenied, SA_Abort, EL_Unknown );
272         break;
273     case ENFILE:
274     case EMFILE:
275         DOS_ERROR( ER_NoMoreFiles, EC_MediaError, SA_Abort, EL_Unknown );
276         break;
277     case EEXIST:
278         DOS_ERROR( ER_FileExists, EC_Exists, SA_Abort, EL_Disk );
279         break;
280     default:
281         perror( "int21: unknown errno" );
282         DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort, EL_Unknown );
283         break;
284     }
285 }
286
287
288 /***********************************************************************
289  *           FILE_DupUnixHandle
290  *
291  * Duplicate a Unix handle into a task handle.
292  */
293 HFILE FILE_DupUnixHandle( int fd )
294 {
295     HFILE handle;
296     DOS_FILE *file;
297
298     if (!(file = FILE_Alloc())) return HFILE_ERROR;
299     if ((file->unix_handle = dup(fd)) == -1)
300     {
301         FILE_SetDosError();
302         FILE_Close( file );
303         return HFILE_ERROR;
304     }
305     if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
306         FILE_Close( file );
307     return handle;
308 }
309
310
311 /***********************************************************************
312  *           FILE_OpenUnixFile
313  */
314 static DOS_FILE *FILE_OpenUnixFile( const char *name, int mode )
315 {
316     DOS_FILE *file;
317     struct stat st;
318
319     if (!(file = FILE_Alloc())) return NULL;
320     if ((file->unix_handle = open( name, mode, 0666 )) == -1)
321     {
322         if (Options.allowReadOnly && (mode == O_RDWR))
323         {
324             if ((file->unix_handle = open( name, O_RDONLY )) != -1)
325                 fprintf( stderr, "Warning: could not open %s for writing, opening read-only.\n", name );
326         }
327     }
328     if ((file->unix_handle == -1) || (fstat( file->unix_handle, &st ) == -1))
329     {
330         FILE_SetDosError();
331         FILE_Close( file );
332         return NULL;
333     }
334     if (S_ISDIR(st.st_mode))
335     {
336         DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
337         FILE_Close( file );
338         return NULL;
339     }
340
341     /* File opened OK, now fill the DOS_FILE */
342
343     file->unix_name = xstrdup( name );
344     DOSFS_ToDosDateTime( st.st_mtime, &file->filedate, &file->filetime );
345     return file;
346 }
347
348
349 /***********************************************************************
350  *           FILE_Open
351  */
352 HFILE FILE_Open( LPCSTR path, INT32 mode )
353 {
354     const char *unixName;
355     DOS_FILE *file;
356     HFILE handle;
357
358     dprintf_file(stddeb, "FILE_Open: '%s' %04x\n", path, mode );
359     if ((unixName = DOSFS_IsDevice( path )) != NULL)
360     {
361         dprintf_file( stddeb, "FILE_Open: opening device '%s'\n", unixName );
362         if (!unixName[0])  /* Non-existing device */
363         {
364             dprintf_file(stddeb, "FILE_Open: Non-existing device\n");
365             DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
366             return HFILE_ERROR;
367         }
368     }
369     else /* check for filename, don't check for last entry if creating */
370         if (!(unixName = DOSFS_GetUnixFileName( path, !(mode & O_CREAT) )))
371             return HFILE_ERROR;
372
373     if (!(file = FILE_OpenUnixFile( unixName, mode ))) return HFILE_ERROR;
374     if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
375         FILE_Close( file );
376     return handle;
377 }
378
379
380 /***********************************************************************
381  *           FILE_Create
382  */
383 static DOS_FILE *FILE_Create( LPCSTR path, int mode, int unique )
384 {
385     DOS_FILE *file;
386     const char *unixName;
387
388     dprintf_file(stddeb, "FILE_Create: '%s' %04x %d\n", path, mode, unique );
389
390     if ((unixName = DOSFS_IsDevice( path )) != NULL)
391     {
392         dprintf_file(stddeb, "FILE_Create: creating device '%s'!\n", unixName);
393         DOS_ERROR( ER_AccessDenied, EC_NotFound, SA_Abort, EL_Disk );
394         return NULL;
395     }
396
397     if (!(file = FILE_Alloc())) return NULL;
398
399     if (!(unixName = DOSFS_GetUnixFileName( path, FALSE )))
400     {
401         FILE_Close( file );
402         return NULL;
403     }
404     if ((file->unix_handle = open( unixName,
405                            O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
406                            mode )) == -1)
407     {
408         FILE_SetDosError();
409         FILE_Close( file );
410         return NULL;
411     } 
412
413     /* File created OK, now fill the DOS_FILE */
414
415     file->unix_name = xstrdup( unixName );
416     DOSFS_ToDosDateTime( time(NULL), &file->filedate, &file->filetime );
417     return file;
418 }
419
420
421 /***********************************************************************
422  *           FILE_Stat
423  *
424  * Stat a Unix path name. Return 1 if OK.
425  */
426 int FILE_Stat( LPCSTR unixName, BYTE *pattr, DWORD *psize,
427                WORD *pdate, WORD *ptime )
428 {
429     struct stat st;
430
431     if (stat( unixName, &st ) == -1)
432     {
433         FILE_SetDosError();
434         return 0;
435     }
436     if (pattr) *pattr = FA_ARCHIVE | (S_ISDIR(st.st_mode) ? FA_DIRECTORY : 0);
437     if (psize) *psize = S_ISDIR(st.st_mode) ? 0 : st.st_size;
438     DOSFS_ToDosDateTime( st.st_mtime, pdate, ptime );
439     return 1;
440 }
441
442
443 /***********************************************************************
444  *           FILE_GetDateTime
445  *
446  * Get the date and time of a file.
447  */
448 int FILE_GetDateTime( HFILE hFile, WORD *pdate, WORD *ptime, BOOL32 refresh )
449 {
450     DOS_FILE *file;
451
452     if (!(file = FILE_GetFile( hFile ))) return 0;
453     if (refresh)
454     {
455         struct stat st;
456         if (fstat( file->unix_handle, &st ) == -1)
457         {
458             FILE_SetDosError();
459             return 0;
460         }
461         DOSFS_ToDosDateTime( st.st_mtime, &file->filedate, &file->filetime );
462     }
463     *pdate = file->filedate;
464     *ptime = file->filetime;
465     return 1;
466 }
467
468
469 /***********************************************************************
470  *           FILE_SetDateTime
471  *
472  * Set the date and time of a file.
473  */
474 int FILE_SetDateTime( HFILE hFile, WORD date, WORD time )
475 {
476     DOS_FILE *file;
477     struct tm newtm;
478     struct utimbuf filetime;
479
480     if (!(file = FILE_GetFile( hFile ))) return 0;
481     newtm.tm_sec  = (time & 0x1f) * 2;
482     newtm.tm_min  = (time >> 5) & 0x3f;
483     newtm.tm_hour = (time >> 11);
484     newtm.tm_mday = (date & 0x1f);
485     newtm.tm_mon  = ((date >> 5) & 0x0f) - 1;
486     newtm.tm_year = (date >> 9) + 80;
487
488     filetime.actime = filetime.modtime = mktime( &newtm );
489     if (utime( file->unix_name, &filetime ) != -1) return 1;
490     FILE_SetDosError();
491     return 0;
492 }
493
494
495 /***********************************************************************
496  *           FILE_Dup
497  *
498  * dup() function for DOS handles.
499  */
500 HFILE FILE_Dup( HFILE hFile )
501 {
502     DOS_FILE *file;
503     HFILE handle;
504
505     dprintf_file( stddeb, "FILE_Dup for handle %d\n", hFile );
506     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
507     if ((handle = FILE_AllocTaskHandle( file )) != HFILE_ERROR) file->count++;
508     dprintf_file( stddeb, "FILE_Dup return handle %d\n", handle );
509     return handle;
510 }
511
512
513 /***********************************************************************
514  *           FILE_Dup2
515  *
516  * dup2() function for DOS handles.
517  */
518 HFILE FILE_Dup2( HFILE hFile1, HFILE hFile2 )
519 {
520     DOS_FILE *file;
521     PDB *pdb = (PDB *)GlobalLock16( GetCurrentPDB() );
522     BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
523
524     dprintf_file( stddeb, "FILE_Dup2 for handle %d\n", hFile1 );
525     if (!(file = FILE_GetFile( hFile1 ))) return HFILE_ERROR;
526
527     if ((hFile2 < 0) || (hFile2 >= (INT)pdb->nbFiles))
528     {
529         DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
530         return HFILE_ERROR;
531     }
532     if (files[hFile2] < MAX_OPEN_FILES)
533     {
534         dprintf_file( stddeb, "FILE_Dup2 closing old handle2 %d\n",
535                       files[hFile2] );
536         FILE_Close( &DOSFiles[files[hFile2]] );
537     }
538     files[hFile2] = (BYTE)(file - DOSFiles);
539     file->count++;
540     dprintf_file( stddeb, "FILE_Dup2 return handle2 %d\n", hFile2 );
541     return hFile2;
542 }
543
544
545 /***********************************************************************
546  *           GetTempFileName16   (KERNEL.97)
547  */
548 UINT16 GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique,
549                           LPSTR buffer )
550 {
551     char temppath[144];
552
553     if ((drive & TF_FORCEDRIVE) &&
554         !DRIVE_IsValid( toupper(drive & ~TF_FORCEDRIVE) - 'A' ))
555     {
556         drive &= ~TF_FORCEDRIVE;
557         fprintf( stderr, "Warning: GetTempFileName: invalid drive %d specified\n",
558                  drive );
559     }
560
561     if (drive & TF_FORCEDRIVE)
562         sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE );
563     else
564     {
565         GetTempPath32A( 132, temppath );
566         strcat( temppath, "\\" );
567     }
568     return (UINT16)GetTempFileName32A( temppath, prefix, unique, buffer );
569 }
570
571
572 /***********************************************************************
573  *           GetTempFileName32A   (KERNEL32.290)
574  */
575 UINT32 GetTempFileName32A( LPCSTR path, LPCSTR prefix, UINT32 unique,
576                            LPSTR buffer)
577 {
578     LPSTR p;
579     int i;
580     UINT32 num = unique ? (unique & 0xffff) : time(NULL) & 0xffff;
581
582     if (!path) return 0;
583     strcpy( buffer, path );
584     p = buffer + strlen(buffer);
585     *p++ = '~';
586     for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
587     sprintf( p, "%04x.tmp", num );
588
589     if (unique)
590     {
591         lstrcpyn32A( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
592         dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
593         if (-1==access(DOSFS_GetUnixFileName(buffer,TRUE),W_OK))
594             fprintf(stderr,"Warning: GetTempFileName returns '%s', which doesn't seem to be writeable. Please check your configuration file if this generates a failure.\n",buffer);
595         return unique;
596     }
597
598     /* Now try to create it */
599
600     do
601     {
602         DOS_FILE *file;
603         if ((file = FILE_Create( buffer, 0666, TRUE )) != NULL)
604         {  /* We created it */
605             dprintf_file( stddeb, "GetTempFileName: created %s\n", buffer );
606             FILE_Close( file );
607             break;
608         }
609         if (DOS_ExtendedError != ER_FileExists) break;  /* No need to go on */
610         num++;
611         sprintf( p, "%04x.tmp", num );
612     } while (num != (unique & 0xffff));
613
614     lstrcpyn32A( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
615     dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
616     if (-1==access(DOSFS_GetUnixFileName(buffer,TRUE),W_OK))
617         fprintf(stderr,"Warning: GetTempFileName returns '%s', which doesn't seem to be writeable. Please check your configuration file if this generates a failure.\n",buffer);
618     return num;
619 }
620
621
622 /***********************************************************************
623  *           GetTempFileName32W   (KERNEL32.291)
624  */
625 UINT32 GetTempFileName32W( LPCWSTR path, LPCWSTR prefix, UINT32 unique,
626                            LPWSTR buffer )
627 {
628     LPSTR   patha,prefixa;
629     char    buffera[144];
630     UINT32  ret;
631
632     if (!path) return 0;
633     patha       = STRING32_DupUniToAnsi(path);
634     prefixa     = STRING32_DupUniToAnsi(prefix);
635     ret         = GetTempFileName32A( patha, prefixa, unique, buffera );
636     STRING32_AnsiToUni( buffer, buffera );
637     free(patha);
638     free(prefixa);
639     return ret;
640 }
641
642
643 /***********************************************************************
644  *           OpenFile   (KERNEL.74) (KERNEL32.396)
645  */
646 HFILE OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT32 mode )
647 {
648     DOS_FILE *file;
649     HFILE hFileRet;
650     WORD filedatetime[2];
651     const char *unixName, *dosName;
652     char *p;
653     int len, i, unixMode;
654
655     ofs->cBytes = sizeof(OFSTRUCT);
656     ofs->nErrCode = 0;
657     if (mode & OF_REOPEN) name = ofs->szPathName;
658     dprintf_file( stddeb, "OpenFile: %s %04x\n", name, mode );
659
660     /* First allocate a task handle */
661
662     if ((hFileRet = FILE_AllocTaskHandle( NULL )) == HFILE_ERROR)
663     {
664         ofs->nErrCode = DOS_ExtendedError;
665         dprintf_file( stddeb, "OpenFile: no more task handles.\n" );
666         return HFILE_ERROR;
667     }
668
669     /* OF_PARSE simply fills the structure */
670
671     if (mode & OF_PARSE)
672     {
673         if (!(dosName = DOSFS_GetDosTrueName( name, FALSE ))) goto error;
674         lstrcpyn32A( ofs->szPathName, dosName, sizeof(ofs->szPathName) );
675         ofs->fFixedDisk = (GetDriveType16( dosName[0]-'A' ) != DRIVE_REMOVABLE);
676         dprintf_file( stddeb, "OpenFile(%s): OF_PARSE, res = '%s', %d\n",
677                       name, ofs->szPathName, hFileRet );
678         /* Return the handle, but close it first */
679         FILE_FreeTaskHandle( hFileRet );
680 /*        return hFileRet; */
681         return 0;  /* Progman seems to like this better */
682     }
683
684     /* OF_CREATE is completely different from all other options, so
685        handle it first */
686
687     if (mode & OF_CREATE)
688     {
689         if (!(file = FILE_Create( name, 0666, FALSE ))) goto error;
690         lstrcpyn32A( ofs->szPathName, DOSFS_GetDosTrueName( name, FALSE ),
691                      sizeof(ofs->szPathName) );
692         goto success;
693     }
694
695     /* Now look for the file */
696
697     /* First try the current directory */
698
699     lstrcpyn32A( ofs->szPathName, name, sizeof(ofs->szPathName) );
700     if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
701         goto found;
702
703     /* Now try some different paths if none was specified */
704
705     if ((mode & OF_SEARCH) && !(mode & OF_REOPEN))
706     {
707         if (name[1] == ':') name += 2;
708         if ((p = strrchr( name, '\\' ))) name = p + 1;
709         if ((p = strrchr( name, '/' ))) name = p + 1;
710         if (!name[0]) goto not_found;
711     }
712     else
713     {
714         if ((name[1] == ':') || strchr( name, '/' ) || strchr( name, '\\' ))
715             goto not_found;
716     }
717
718     if ((len = sizeof(ofs->szPathName) - strlen(name) - 1) < 0) goto not_found;
719
720     /* Try the Windows directory */
721
722     GetWindowsDirectory32A( ofs->szPathName, len );
723     strcat( ofs->szPathName, "\\" );
724     strcat( ofs->szPathName, name );
725     if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
726         goto found;
727
728     /* Try the Windows system directory */
729
730     GetSystemDirectory32A( ofs->szPathName, len );
731     strcat( ofs->szPathName, "\\" );
732     strcat( ofs->szPathName, name );
733     if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )) != NULL)
734         goto found;
735
736     /* Try the path of the current executable */
737
738     if (GetCurrentTask())
739     {
740         GetModuleFileName16( GetCurrentTask(), ofs->szPathName, len );
741         if ((p = strrchr( ofs->szPathName, '\\' )))
742         {
743             strcpy( p + 1, name );
744             if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE )))
745                 goto found;
746         }
747     }
748
749     /* Try all directories in path */
750
751     for (i = 0; ; i++)
752     {
753         if (!DIR_GetDosPath( i, ofs->szPathName, len )) goto not_found;
754         strcat( ofs->szPathName, "\\" );
755         strcat( ofs->szPathName, name );
756         if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE)) != NULL)
757             break;
758     }
759
760 found:
761     dprintf_file( stddeb, "OpenFile: found '%s'\n", unixName );
762     lstrcpyn32A(ofs->szPathName, DOSFS_GetDosTrueName( ofs->szPathName, FALSE),
763                 sizeof(ofs->szPathName) );
764
765     if (mode & OF_DELETE)
766     {
767         if (unlink( unixName ) == -1) goto not_found;
768         dprintf_file( stddeb, "OpenFile(%s): OF_DELETE return = OK\n", name);
769         /* Return the handle, but close it first */
770         FILE_FreeTaskHandle( hFileRet );
771         return hFileRet;
772     }
773
774     switch(mode & 3)
775     {
776     case OF_WRITE:
777         unixMode = O_WRONLY; break;
778     case OF_READWRITE:
779         unixMode = O_RDWR; break;
780     case OF_READ:
781     default:
782         unixMode = O_RDONLY; break;
783     }
784
785     if (!(file = FILE_OpenUnixFile( unixName, unixMode ))) goto not_found;
786     filedatetime[0] = file->filedate;
787     filedatetime[1] = file->filetime;
788     if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
789     {
790         if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
791         {
792             FILE_Close( file );
793             dprintf_file( stddeb, "OpenFile(%s): OF_VERIFY failed\n", name );
794             /* FIXME: what error here? */
795             DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
796             goto error;
797         }
798     }
799     memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
800
801     if (mode & OF_EXIST)
802     {
803         FILE_Close( file );
804         /* Return the handle, but close it first */
805         FILE_FreeTaskHandle( hFileRet );
806         return hFileRet;
807     }
808
809 success:  /* We get here if the open was successful */
810     dprintf_file( stddeb, "OpenFile(%s): OK, return = %d\n", name, hFileRet );
811     FILE_SetTaskHandle( hFileRet, file );
812     return hFileRet;
813
814 not_found:  /* We get here if the file does not exist */
815     dprintf_file( stddeb, "OpenFile: '%s' not found\n", name );
816     DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
817     /* fall through */
818
819 error:  /* We get here if there was an error opening the file */
820     ofs->nErrCode = DOS_ExtendedError;
821     dprintf_file( stddeb, "OpenFile(%s): return = HFILE_ERROR\n", name );
822     FILE_FreeTaskHandle( hFileRet );
823     return HFILE_ERROR;
824 }
825
826 /***********************************************************************
827  *           SearchPath32A   (KERNEL32.447)
828  * Code borrowed from OpenFile above.
829  */
830 DWORD SearchPath32A(
831         LPCSTR path,LPCSTR fn,LPCSTR ext,DWORD buflen,LPSTR buf,LPSTR *lastpart
832 ) {
833     LPCSTR      unixName;
834     INT32       len;
835     char        testpath[1000]; /* should be enough for now */
836     char        *name,*p;
837     int         i;
838
839     if (ext==NULL)
840         ext = "";
841     name=(char*)xmalloc(strlen(fn)+strlen(ext)+1);
842     strcpy(name,fn);
843     strcat(name,ext);
844
845     dprintf_file(stddeb,"SearchPath32A(%s,%s,%s,%ld,%p,%p)\n",
846         path,fn,ext,buflen,buf,lastpart
847     );
848     if (path) {
849         strcpy(testpath,path);
850         strcat(testpath,"\\");
851         strcat(testpath,name);
852         if ((unixName=DOSFS_GetUnixFileName((LPCSTR)testpath,TRUE))!=NULL) {
853             goto found;
854         } else {
855             strcpy(testpath,name);
856             if ((unixName=DOSFS_GetUnixFileName((LPCSTR)testpath,TRUE))!=NULL)
857                 goto found;
858             return 0;
859         }
860     }
861     if ((len=sizeof(testpath)-strlen(name)-1)<0)
862         return 0;
863
864     /* Try the path of the current executable */
865     if (GetCurrentTask()) {
866         GetModuleFileName16(GetCurrentTask(),testpath,len);
867         if ((p=strrchr(testpath,'\\'))) {
868             strcpy(p+1,name);
869             if ((unixName=DOSFS_GetUnixFileName((LPCSTR)testpath,TRUE)))
870                 goto found;
871         }
872     }
873
874     /* Try the current directory */
875     lstrcpyn32A(testpath,name,sizeof(testpath) );
876     if ((unixName=DOSFS_GetUnixFileName((LPCSTR)testpath,TRUE))!=NULL)
877         goto found;
878
879     /* Try the Windows directory */
880     GetWindowsDirectory32A(testpath,len);
881     strcat(testpath,"\\");
882     strcat(testpath,name);
883     if ((unixName = DOSFS_GetUnixFileName((LPCSTR)testpath,TRUE))!=NULL)
884         goto found;
885
886     /* Try the Windows system directory */
887     GetSystemDirectory32A(testpath,len);
888     strcat(testpath,"\\");
889     strcat(testpath,name);
890     if ((unixName=DOSFS_GetUnixFileName((LPCSTR)testpath,TRUE))!=NULL)
891         goto found;
892
893     /* Try all directories in path */
894
895     for (i=0;;i++)
896     {
897         if (!DIR_GetDosPath(i,testpath,len)) 
898                 return 0;
899         strcat(testpath,"\\");
900         strcat(testpath,name);
901         if ((unixName=DOSFS_GetUnixFileName((LPCSTR)testpath,TRUE))!=NULL)
902             break;
903     }
904
905 found:
906     strncpy(buf,testpath,buflen);
907     if (NULL!=(p=strrchr(testpath,'\\')))
908         p=p+1;
909     else
910         p=testpath;
911     if (lastpart) {
912         if (p-testpath<buflen)
913             *lastpart=(p-testpath)+buf;
914         else
915             *lastpart=NULL;
916     }
917     dprintf_file(stddeb,"       -> found %s,last part is %s\n",testpath,p);
918     return strlen(testpath);
919 }
920
921 /***********************************************************************
922  *           SearchPath32W   (KERNEL32.448)
923  */
924 DWORD SearchPath32W(
925         LPCWSTR path,LPCWSTR fn,LPCWSTR ext,DWORD buflen,LPWSTR buf,
926         LPWSTR *lastpart
927 ) {
928         LPSTR   pathA = path?STRING32_DupUniToAnsi(path):NULL;
929         LPSTR   fnA = STRING32_DupUniToAnsi(fn);
930         LPSTR   extA = ext?STRING32_DupUniToAnsi(fn):NULL;
931         LPSTR   lastpartA;
932         LPSTR   bufA = (char*)xmalloc(buflen+1);
933         DWORD   ret;
934
935         ret=SearchPath32A(pathA,fnA,extA,buflen,bufA,&lastpartA);
936         lstrcpynAtoW(buf,bufA,buflen);
937         if (lastpart) {
938                 if (lastpartA)
939                         *lastpart = buf+(lastpartA-bufA);
940                 else
941                         *lastpart = NULL;
942         }
943         free(bufA);
944         free(fnA);
945         if (pathA) free(pathA);
946         if (extA) free(extA);
947         return ret;
948 }
949
950 /***********************************************************************
951  *           _lclose   (KERNEL.81) (KERNEL32.592)
952  */
953 HFILE _lclose( HFILE hFile )
954 {
955     DOS_FILE *file;
956
957     dprintf_file( stddeb, "_lclose: handle %d\n", hFile );
958     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
959     FILE_Close( file );
960     FILE_FreeTaskHandle( hFile );
961     return 0;
962 }
963
964
965 /***********************************************************************
966  *           WIN16_hread
967  */
968 LONG WIN16_hread( HFILE hFile, SEGPTR buffer, LONG count )
969 {
970     LONG maxlen;
971
972     dprintf_file( stddeb, "_hread16: %d %08lx %ld\n",
973                   hFile, (DWORD)buffer, count );
974
975     /* Some programs pass a count larger than the allocated buffer */
976     maxlen = GetSelectorLimit( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
977     if (count > maxlen) count = maxlen;
978     return _lread32( hFile, PTR_SEG_TO_LIN(buffer), count );
979 }
980
981
982 /***********************************************************************
983  *           WIN16_lread
984  */
985 UINT16 WIN16_lread( HFILE hFile, SEGPTR buffer, UINT16 count )
986 {
987     return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
988 }
989
990
991 /***********************************************************************
992  *           _lread32   (KERNEL32.596)
993  */
994 UINT32 _lread32( HFILE hFile, LPVOID buffer, UINT32 count )
995 {
996     DOS_FILE *file;
997     UINT32 result;
998
999     dprintf_file( stddeb, "_lread32: %d %p %d\n", hFile, buffer, count );
1000     if (!(file = FILE_GetFile( hFile ))) return -1;
1001     if (!count) return 0;
1002     if ((result = read( file->unix_handle, buffer, count )) == -1)
1003         FILE_SetDosError();
1004     return result;
1005 }
1006
1007
1008 /***********************************************************************
1009  *           _lread16   (KERNEL.82)
1010  */
1011 UINT16 _lread16( HFILE hFile, LPVOID buffer, UINT16 count )
1012 {
1013     return (UINT16)_lread32( hFile, buffer, (LONG)count );
1014 }
1015
1016
1017 /***********************************************************************
1018  *           _lcreat   (KERNEL.83) (KERNEL32.593)
1019  */
1020 HFILE _lcreat( LPCSTR path, INT32 attr )
1021 {
1022     DOS_FILE *file;
1023     HFILE handle;
1024     int mode;
1025     
1026     dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
1027     mode = (attr & 1) ? 0444 : 0666;
1028     if (!(file = FILE_Create( path, mode, FALSE ))) return HFILE_ERROR;
1029     if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
1030         FILE_Close( file );
1031     return handle;
1032 }
1033
1034
1035 /***********************************************************************
1036  *           _lcreat_uniq   (Not a Windows API)
1037  */
1038 HFILE _lcreat_uniq( LPCSTR path, INT32 attr )
1039 {
1040     DOS_FILE *file;
1041     HFILE handle;
1042     int mode;
1043     
1044     dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
1045     mode = (attr & 1) ? 0444 : 0666;
1046     if (!(file = FILE_Create( path, mode, TRUE ))) return HFILE_ERROR;
1047     if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
1048         FILE_Close( file );
1049     return handle;
1050 }
1051
1052
1053 /***********************************************************************
1054  *           _llseek   (KERNEL.84) (KERNEL32.594)
1055  */
1056 LONG _llseek( HFILE hFile, LONG lOffset, INT32 nOrigin )
1057 {
1058     DOS_FILE *file;
1059     int origin, result;
1060
1061     dprintf_file( stddeb, "_llseek: handle %d, offset %ld, origin %d\n", 
1062                   hFile, lOffset, nOrigin);
1063
1064     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
1065     switch(nOrigin)
1066     {
1067         case 1:  origin = SEEK_CUR; break;
1068         case 2:  origin = SEEK_END; break;
1069         default: origin = SEEK_SET; break;
1070     }
1071
1072     if ((result = lseek( file->unix_handle, lOffset, origin )) == -1)
1073         FILE_SetDosError();
1074     return result;
1075 }
1076
1077
1078 /***********************************************************************
1079  *           _lopen   (KERNEL.85) (KERNEL32.595)
1080  */
1081 HFILE _lopen( LPCSTR path, INT32 mode )
1082 {
1083     INT32 unixMode;
1084
1085     dprintf_file(stddeb, "_lopen('%s',%04x)\n", path, mode );
1086
1087     switch(mode & 3)
1088     {
1089     case OF_WRITE:
1090         unixMode = O_WRONLY | O_TRUNC;
1091         break;
1092     case OF_READWRITE:
1093         unixMode = O_RDWR;
1094         break;
1095     case OF_READ:
1096     default:
1097         unixMode = O_RDONLY;
1098         break;
1099     }
1100     return FILE_Open( path, unixMode );
1101 }
1102
1103
1104 /***********************************************************************
1105  *           _lwrite16   (KERNEL.86)
1106  */
1107 UINT16 _lwrite16( HFILE hFile, LPCSTR buffer, UINT16 count )
1108 {
1109     return (UINT16)_hwrite( hFile, buffer, (LONG)count );
1110 }
1111
1112 /***********************************************************************
1113  *           _lwrite32   (KERNEL.86)
1114  */
1115 UINT32 _lwrite32( HFILE hFile, LPCSTR buffer, UINT32 count )
1116 {
1117     return (UINT32)_hwrite( hFile, buffer, (LONG)count );
1118 }
1119
1120
1121 /***********************************************************************
1122  *           _hread   (KERNEL.349)
1123  */
1124 LONG _hread( HFILE hFile, LPVOID buffer, LONG count)
1125 {
1126     return _lread32( hFile, buffer, count );
1127 }
1128
1129
1130 /***********************************************************************
1131  *           _hwrite   (KERNEL.350)
1132  */
1133 LONG _hwrite( HFILE hFile, LPCSTR buffer, LONG count )
1134 {
1135     DOS_FILE *file;
1136     LONG result;
1137
1138     dprintf_file( stddeb, "_hwrite: %d %p %ld\n", hFile, buffer, count );
1139
1140     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
1141     
1142     if (count == 0)  /* Expand or truncate at current position */
1143         result = ftruncate( file->unix_handle,
1144                             lseek( file->unix_handle, 0, SEEK_CUR ) );
1145     else
1146         result = write( file->unix_handle, buffer, count );
1147
1148     if (result == -1) FILE_SetDosError();
1149     return result;
1150 }
1151
1152
1153 /***********************************************************************
1154  *           SetHandleCount16   (KERNEL.199)
1155  */
1156 UINT16 SetHandleCount16( UINT16 count )
1157 {
1158     HGLOBAL16 hPDB = GetCurrentPDB();
1159     PDB *pdb = (PDB *)GlobalLock16( hPDB );
1160     BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
1161     WORD i;
1162
1163     dprintf_file( stddeb, "SetHandleCount(%d)\n", count );
1164
1165     if (count < 20) count = 20;  /* No point in going below 20 */
1166     else if (count > 254) count = 254;
1167
1168     /* If shrinking the table, make sure all extra file handles are closed */
1169     if (count < pdb->nbFiles)
1170     {
1171         for (i = count; i < pdb->nbFiles; i++)
1172             if (files[i] != 0xff)  /* File open */
1173             {
1174                 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError,
1175                            SA_Abort, EL_Disk );
1176                 return pdb->nbFiles;
1177             }
1178     }
1179
1180     if (count == 20)
1181     {
1182         if (pdb->nbFiles > 20)
1183         {
1184             memcpy( pdb->fileHandles, files, 20 );
1185 #ifdef WINELIB
1186             GlobalFree32( (HGLOBAL32)pdb->fileHandlesPtr );
1187             pdb->fileHandlesPtr = (SEGPTR)pdb->fileHandles;
1188 #else
1189             GlobalFree16( GlobalHandle16( SELECTOROF(pdb->fileHandlesPtr) ));
1190             pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
1191                                                    GlobalHandleToSel( hPDB ) );
1192 #endif
1193             pdb->nbFiles = 20;
1194         }
1195     }
1196     else  /* More than 20, need a new file handles table */
1197     {
1198         BYTE *newfiles;
1199 #ifdef WINELIB
1200         newfiles = (BYTE *)GlobalAlloc32( GMEM_FIXED, count );
1201 #else
1202         HGLOBAL16 newhandle = GlobalAlloc16( GMEM_MOVEABLE, count );
1203         if (!newhandle)
1204         {
1205             DOS_ERROR( ER_OutOfMemory, EC_OutOfResource, SA_Abort, EL_Memory );
1206             return pdb->nbFiles;
1207         }
1208         newfiles = (BYTE *)GlobalLock16( newhandle );
1209 #endif  /* WINELIB */
1210         if (count > pdb->nbFiles)
1211         {
1212             memcpy( newfiles, files, pdb->nbFiles );
1213             memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1214         }
1215         else memcpy( newfiles, files, count );
1216 #ifdef WINELIB
1217         if (pdb->nbFiles > 20) GlobalFree32( (HGLOBAL32)pdb->fileHandlesPtr );
1218         pdb->fileHandlesPtr = (SEGPTR)newfiles;
1219 #else
1220         if (pdb->nbFiles > 20)
1221             GlobalFree16( GlobalHandle16( SELECTOROF(pdb->fileHandlesPtr) ));
1222         pdb->fileHandlesPtr = WIN16_GlobalLock16( newhandle );
1223 #endif  /* WINELIB */
1224         pdb->nbFiles = count;
1225     }
1226     return pdb->nbFiles;
1227 }
1228
1229
1230 /***********************************************************************
1231  *           FlushFileBuffers   (KERNEL32.133)
1232  */
1233 BOOL32 FlushFileBuffers( HFILE hFile )
1234 {
1235     DOS_FILE *file;
1236
1237     dprintf_file( stddeb, "FlushFileBuffers(%d)\n", hFile );
1238     if (!(file = FILE_GetFile( hFile ))) return FALSE;
1239     if (fsync( file->unix_handle ) != -1) return TRUE;
1240     FILE_SetDosError();
1241     return FALSE;
1242 }
1243
1244
1245 /***********************************************************************
1246  *           DeleteFile16   (KERNEL.146)
1247  */
1248 BOOL16 DeleteFile16( LPCSTR path )
1249 {
1250     return DeleteFile32A( path );
1251 }
1252
1253
1254 /***********************************************************************
1255  *           DeleteFile32A   (KERNEL32.71)
1256  */
1257 BOOL32 DeleteFile32A( LPCSTR path )
1258 {
1259     const char *unixName;
1260
1261     dprintf_file(stddeb, "DeleteFile: '%s'\n", path );
1262
1263     if ((unixName = DOSFS_IsDevice( path )) != NULL)
1264     {
1265         dprintf_file(stddeb, "DeleteFile: removing device '%s'!\n", unixName);
1266         DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
1267         return FALSE;
1268     }
1269
1270     if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return FALSE;
1271     if (unlink( unixName ) == -1)
1272     {
1273         FILE_SetDosError();
1274         return FALSE;
1275     }
1276     return TRUE;
1277 }
1278
1279
1280 /***********************************************************************
1281  *           DeleteFile32W   (KERNEL32.72)
1282  */
1283 BOOL32 DeleteFile32W( LPCWSTR path )
1284 {
1285     LPSTR xpath = STRING32_DupUniToAnsi(path);
1286     BOOL32 ret = RemoveDirectory32A( xpath );
1287     free(xpath);
1288     return ret;
1289 }
1290
1291
1292 /***********************************************************************
1293  *           CreateDirectory16   (KERNEL.144)
1294  */
1295 BOOL16 CreateDirectory16( LPCSTR path, LPVOID dummy )
1296 {
1297     dprintf_file( stddeb,"CreateDirectory16(%s,%p)\n", path, dummy );
1298     return (BOOL16)CreateDirectory32A( path, NULL );
1299 }
1300
1301
1302 /***********************************************************************
1303  *           CreateDirectory32A   (KERNEL32.39)
1304  */
1305 BOOL32 CreateDirectory32A( LPCSTR path, LPSECURITY_ATTRIBUTES lpsecattribs )
1306 {
1307     const char *unixName;
1308
1309     dprintf_file( stddeb, "CreateDirectory32A(%s,%p)\n", path, lpsecattribs );
1310     if ((unixName = DOSFS_IsDevice( path )) != NULL)
1311     {
1312         dprintf_file(stddeb, "CreateDirectory: device '%s'!\n", unixName);
1313         DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
1314         return FALSE;
1315     }
1316     if (!(unixName = DOSFS_GetUnixFileName( path, FALSE ))) return 0;
1317     if ((mkdir( unixName, 0777 ) == -1) && (errno != EEXIST))
1318     {
1319         FILE_SetDosError();
1320         return FALSE;
1321     }
1322     return TRUE;
1323 }
1324
1325
1326 /***********************************************************************
1327  *           CreateDirectory32W   (KERNEL32.42)
1328  */
1329 BOOL32 CreateDirectory32W( LPCWSTR path, LPSECURITY_ATTRIBUTES lpsecattribs )
1330 {
1331     LPSTR xpath = STRING32_DupUniToAnsi(path);
1332     BOOL32 ret = CreateDirectory32A(xpath,lpsecattribs);
1333     free(xpath);
1334     return ret;
1335 }
1336
1337 /***********************************************************************
1338  *           CreateDirectoryEx32A   (KERNEL32.40)
1339  */
1340 BOOL32 CreateDirectoryEx32A( LPCSTR template, LPCSTR path,
1341                              LPSECURITY_ATTRIBUTES lpsecattribs)
1342 {
1343     return CreateDirectory32A(path,lpsecattribs);
1344 }
1345
1346 /***********************************************************************
1347  *           CreateDirectoryEx32W   (KERNEL32.41)
1348  */
1349 BOOL32 CreateDirectoryEx32W( LPCWSTR template, LPCWSTR path,
1350                              LPSECURITY_ATTRIBUTES lpsecattribs)
1351 {
1352     return CreateDirectory32W(path,lpsecattribs);
1353 }
1354
1355 /***********************************************************************
1356  *           RemoveDirectory16   (KERNEL)
1357  */
1358 BOOL16 RemoveDirectory16( LPCSTR path )
1359 {
1360     return (BOOL16)RemoveDirectory32A( path );
1361 }
1362
1363
1364 /***********************************************************************
1365  *           RemoveDirectory32A   (KERNEL32.437)
1366  */
1367 BOOL32 RemoveDirectory32A( LPCSTR path )
1368 {
1369     const char *unixName;
1370
1371     dprintf_file(stddeb, "RemoveDirectory: '%s'\n", path );
1372
1373     if ((unixName = DOSFS_IsDevice( path )) != NULL)
1374     {
1375         dprintf_file(stddeb, "RemoveDirectory: device '%s'!\n", unixName);
1376         DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
1377         return FALSE;
1378     }
1379     if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return FALSE;
1380     if (rmdir( unixName ) == -1)
1381     {
1382         FILE_SetDosError();
1383         return FALSE;
1384     }
1385     return TRUE;
1386 }
1387
1388
1389 /***********************************************************************
1390  *           RemoveDirectory32W   (KERNEL32.438)
1391  */
1392 BOOL32 RemoveDirectory32W( LPCWSTR path )
1393 {
1394     LPSTR xpath = STRING32_DupUniToAnsi(path);
1395     BOOL32 ret = RemoveDirectory32A( xpath );
1396     free(xpath);
1397     return ret;
1398 }
1399
1400
1401 /***********************************************************************
1402  *           FILE_SetFileType
1403  */
1404 BOOL32 FILE_SetFileType( HFILE hFile, DWORD type )
1405 {
1406     DOS_FILE *file = FILE_GetFile(hFile);
1407     if (!file) return FALSE;
1408     file->type = type;
1409     return TRUE;
1410 }
1411
1412
1413 /***********************************************************************
1414  *           GetFileType   (KERNEL32.222)
1415  */
1416 DWORD GetFileType( HFILE hFile )
1417 {
1418     DOS_FILE *file = FILE_GetFile(hFile);
1419     
1420     if (!file)
1421     {
1422         SetLastError( ERROR_INVALID_HANDLE );
1423         return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1424     }
1425     return file->type;
1426 }
1427
1428
1429 /***********************************************************************
1430  *              GetFileTime   (KERNEL32.221)
1431  */
1432 BOOL32 GetFileTime( HFILE hFile, FILETIME *lpCreationTime,
1433                     FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime )
1434 {
1435     DOS_FILE *file = FILE_GetFile(hFile);
1436     struct stat stbuf;
1437     
1438     if (!file) {
1439         SetLastError( ERROR_INVALID_HANDLE );
1440         return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1441     }
1442     dprintf_file(stddeb,"SetFileTime(%s,%p,%p,%p)\n",
1443         file->unix_name,
1444         lpCreationTime,
1445         lpLastAccessTime,
1446         lpLastWriteTime
1447     );
1448     if (-1==fstat(file->unix_handle,&stbuf)) {
1449         FILE_SetDosError();
1450         return FALSE;
1451     }
1452     if (lpLastWriteTime)
1453         DOSFS_UnixTimeToFileTime(stbuf.st_mtime,lpLastWriteTime);
1454     if (lpCreationTime)
1455         DOSFS_UnixTimeToFileTime(stbuf.st_ctime,lpCreationTime);
1456     if (lpLastAccessTime)
1457         DOSFS_UnixTimeToFileTime(stbuf.st_atime,lpLastAccessTime);
1458     return TRUE;
1459 }
1460
1461
1462 /***********************************************************************
1463  *              SetFileTime   (KERNEL32.493)
1464  */
1465 BOOL32 SetFileTime( HFILE hFile, FILETIME *lpCreationTime,
1466                     FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime )
1467 {
1468     DOS_FILE *file = FILE_GetFile(hFile);
1469     struct utimbuf utimbuf;
1470     
1471     if (!file) {
1472         SetLastError( ERROR_INVALID_HANDLE );
1473         return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1474     }
1475     dprintf_file(stddeb,"SetFileTime(%s,%p,%p,%p)\n",
1476         file->unix_name,
1477         lpCreationTime,
1478         lpLastAccessTime,
1479         lpLastWriteTime
1480     );
1481     if (lpLastAccessTime)
1482         utimbuf.actime  = DOSFS_FileTimeToUnixTime(lpLastAccessTime);
1483     else
1484         utimbuf.actime  = 0; /* FIXME */
1485     if (lpLastWriteTime)
1486         utimbuf.modtime = DOSFS_FileTimeToUnixTime(lpLastWriteTime);
1487     else
1488         utimbuf.modtime = 0; /* FIXME */
1489     if (-1==utime(file->unix_name,&utimbuf)) {
1490         FILE_SetDosError();
1491         return FALSE;
1492     }
1493     return TRUE;
1494 }