Release 961222
[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 "heap.h"
27 #include "msdos.h"
28 #include "options.h"
29 #include "ldt.h"
30 #include "task.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   = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
634     prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix );
635     ret     = GetTempFileName32A( patha, prefixa, unique, buffera );
636     lstrcpyAtoW( buffer, buffera );
637     HeapFree( GetProcessHeap(), 0, patha );
638     HeapFree( GetProcessHeap(), 0, 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( LPCWSTR path, LPCWSTR fn, LPCWSTR ext, DWORD buflen,
925                      LPWSTR buf, LPWSTR *lastpart )
926 {
927         LPSTR   pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
928         LPSTR   fnA = HEAP_strdupWtoA( GetProcessHeap(), 0, fn );
929         LPSTR   extA = HEAP_strdupWtoA( GetProcessHeap(), 0, ext );
930         LPSTR   lastpartA;
931         LPSTR   bufA = HeapAlloc( GetProcessHeap(), 0, buflen + 1 );
932         DWORD   ret;
933
934         ret = SearchPath32A(pathA,fnA,extA,buflen,bufA,&lastpartA);
935         lstrcpyAtoW( buf, bufA );
936         if (lastpart)
937         {
938             if (lastpartA) *lastpart = buf+(lastpartA-bufA);
939             else *lastpart = NULL;
940         }
941         HeapFree( GetProcessHeap(), 0, bufA );
942         HeapFree( GetProcessHeap(), 0, fnA );
943         HeapFree( GetProcessHeap(), 0, pathA );
944         HeapFree( GetProcessHeap(), 0, extA );
945         return ret;
946 }
947
948 /***********************************************************************
949  *           _lclose   (KERNEL.81) (KERNEL32.592)
950  */
951 HFILE _lclose( HFILE hFile )
952 {
953     DOS_FILE *file;
954
955     dprintf_file( stddeb, "_lclose: handle %d\n", hFile );
956     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
957     FILE_Close( file );
958     FILE_FreeTaskHandle( hFile );
959     return 0;
960 }
961
962
963 /***********************************************************************
964  *           WIN16_hread
965  */
966 LONG WIN16_hread( HFILE hFile, SEGPTR buffer, LONG count )
967 {
968     LONG maxlen;
969
970     dprintf_file( stddeb, "_hread16: %d %08lx %ld\n",
971                   hFile, (DWORD)buffer, count );
972
973     /* Some programs pass a count larger than the allocated buffer */
974     maxlen = GetSelectorLimit( SELECTOROF(buffer) ) - OFFSETOF(buffer) + 1;
975     if (count > maxlen) count = maxlen;
976     return _lread32( hFile, PTR_SEG_TO_LIN(buffer), count );
977 }
978
979
980 /***********************************************************************
981  *           WIN16_lread
982  */
983 UINT16 WIN16_lread( HFILE hFile, SEGPTR buffer, UINT16 count )
984 {
985     return (UINT16)WIN16_hread( hFile, buffer, (LONG)count );
986 }
987
988
989 /***********************************************************************
990  *           _lread32   (KERNEL32.596)
991  */
992 UINT32 _lread32( HFILE hFile, LPVOID buffer, UINT32 count )
993 {
994     DOS_FILE *file;
995     UINT32 result;
996
997     dprintf_file( stddeb, "_lread32: %d %p %d\n", hFile, buffer, count );
998     if (!(file = FILE_GetFile( hFile ))) return -1;
999     if (!count) return 0;
1000     if ((result = read( file->unix_handle, buffer, count )) == -1)
1001         FILE_SetDosError();
1002     return result;
1003 }
1004
1005
1006 /***********************************************************************
1007  *           _lread16   (KERNEL.82)
1008  */
1009 UINT16 _lread16( HFILE hFile, LPVOID buffer, UINT16 count )
1010 {
1011     return (UINT16)_lread32( hFile, buffer, (LONG)count );
1012 }
1013
1014
1015 /***********************************************************************
1016  *           _lcreat   (KERNEL.83) (KERNEL32.593)
1017  */
1018 HFILE _lcreat( LPCSTR path, INT32 attr )
1019 {
1020     DOS_FILE *file;
1021     HFILE handle;
1022     int mode;
1023     
1024     dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
1025     mode = (attr & 1) ? 0444 : 0666;
1026     if (!(file = FILE_Create( path, mode, FALSE ))) return HFILE_ERROR;
1027     if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
1028         FILE_Close( file );
1029     return handle;
1030 }
1031
1032
1033 /***********************************************************************
1034  *           _lcreat_uniq   (Not a Windows API)
1035  */
1036 HFILE _lcreat_uniq( LPCSTR path, INT32 attr )
1037 {
1038     DOS_FILE *file;
1039     HFILE handle;
1040     int mode;
1041     
1042     dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
1043     mode = (attr & 1) ? 0444 : 0666;
1044     if (!(file = FILE_Create( path, mode, TRUE ))) return HFILE_ERROR;
1045     if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
1046         FILE_Close( file );
1047     return handle;
1048 }
1049
1050
1051 /***********************************************************************
1052  *           _llseek   (KERNEL.84) (KERNEL32.594)
1053  */
1054 LONG _llseek( HFILE hFile, LONG lOffset, INT32 nOrigin )
1055 {
1056     DOS_FILE *file;
1057     int origin, result;
1058
1059     dprintf_file( stddeb, "_llseek: handle %d, offset %ld, origin %d\n", 
1060                   hFile, lOffset, nOrigin);
1061
1062     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
1063     switch(nOrigin)
1064     {
1065         case 1:  origin = SEEK_CUR; break;
1066         case 2:  origin = SEEK_END; break;
1067         default: origin = SEEK_SET; break;
1068     }
1069
1070     if ((result = lseek( file->unix_handle, lOffset, origin )) == -1)
1071         FILE_SetDosError();
1072     return result;
1073 }
1074
1075
1076 /***********************************************************************
1077  *           _lopen   (KERNEL.85) (KERNEL32.595)
1078  */
1079 HFILE _lopen( LPCSTR path, INT32 mode )
1080 {
1081     INT32 unixMode;
1082
1083     dprintf_file(stddeb, "_lopen('%s',%04x)\n", path, mode );
1084
1085     switch(mode & 3)
1086     {
1087     case OF_WRITE:
1088         unixMode = O_WRONLY | O_TRUNC;
1089         break;
1090     case OF_READWRITE:
1091         unixMode = O_RDWR;
1092         break;
1093     case OF_READ:
1094     default:
1095         unixMode = O_RDONLY;
1096         break;
1097     }
1098     return FILE_Open( path, unixMode );
1099 }
1100
1101
1102 /***********************************************************************
1103  *           _lwrite16   (KERNEL.86)
1104  */
1105 UINT16 _lwrite16( HFILE hFile, LPCSTR buffer, UINT16 count )
1106 {
1107     return (UINT16)_hwrite( hFile, buffer, (LONG)count );
1108 }
1109
1110 /***********************************************************************
1111  *           _lwrite32   (KERNEL.86)
1112  */
1113 UINT32 _lwrite32( HFILE hFile, LPCSTR buffer, UINT32 count )
1114 {
1115     return (UINT32)_hwrite( hFile, buffer, (LONG)count );
1116 }
1117
1118
1119 /***********************************************************************
1120  *           _hread   (KERNEL.349)
1121  */
1122 LONG _hread( HFILE hFile, LPVOID buffer, LONG count)
1123 {
1124     return _lread32( hFile, buffer, count );
1125 }
1126
1127
1128 /***********************************************************************
1129  *           _hwrite   (KERNEL.350)
1130  */
1131 LONG _hwrite( HFILE hFile, LPCSTR buffer, LONG count )
1132 {
1133     DOS_FILE *file;
1134     LONG result;
1135
1136     dprintf_file( stddeb, "_hwrite: %d %p %ld\n", hFile, buffer, count );
1137
1138     if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
1139     
1140     if (count == 0)  /* Expand or truncate at current position */
1141         result = ftruncate( file->unix_handle,
1142                             lseek( file->unix_handle, 0, SEEK_CUR ) );
1143     else
1144         result = write( file->unix_handle, buffer, count );
1145
1146     if (result == -1) FILE_SetDosError();
1147     return result;
1148 }
1149
1150
1151 /***********************************************************************
1152  *           SetHandleCount16   (KERNEL.199)
1153  */
1154 UINT16 SetHandleCount16( UINT16 count )
1155 {
1156     HGLOBAL16 hPDB = GetCurrentPDB();
1157     PDB *pdb = (PDB *)GlobalLock16( hPDB );
1158     BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
1159     WORD i;
1160
1161     dprintf_file( stddeb, "SetHandleCount(%d)\n", count );
1162
1163     if (count < 20) count = 20;  /* No point in going below 20 */
1164     else if (count > 254) count = 254;
1165
1166     /* If shrinking the table, make sure all extra file handles are closed */
1167     if (count < pdb->nbFiles)
1168     {
1169         for (i = count; i < pdb->nbFiles; i++)
1170             if (files[i] != 0xff)  /* File open */
1171             {
1172                 DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError,
1173                            SA_Abort, EL_Disk );
1174                 return pdb->nbFiles;
1175             }
1176     }
1177
1178     if (count == 20)
1179     {
1180         if (pdb->nbFiles > 20)
1181         {
1182             memcpy( pdb->fileHandles, files, 20 );
1183 #ifdef WINELIB
1184             GlobalFree32( (HGLOBAL32)pdb->fileHandlesPtr );
1185             pdb->fileHandlesPtr = (SEGPTR)pdb->fileHandles;
1186 #else
1187             GlobalFree16( GlobalHandle16( SELECTOROF(pdb->fileHandlesPtr) ));
1188             pdb->fileHandlesPtr = (SEGPTR)MAKELONG( 0x18,
1189                                                    GlobalHandleToSel( hPDB ) );
1190 #endif
1191             pdb->nbFiles = 20;
1192         }
1193     }
1194     else  /* More than 20, need a new file handles table */
1195     {
1196         BYTE *newfiles;
1197 #ifdef WINELIB
1198         newfiles = (BYTE *)GlobalAlloc32( GMEM_FIXED, count );
1199 #else
1200         HGLOBAL16 newhandle = GlobalAlloc16( GMEM_MOVEABLE, count );
1201         if (!newhandle)
1202         {
1203             DOS_ERROR( ER_OutOfMemory, EC_OutOfResource, SA_Abort, EL_Memory );
1204             return pdb->nbFiles;
1205         }
1206         newfiles = (BYTE *)GlobalLock16( newhandle );
1207 #endif  /* WINELIB */
1208         if (count > pdb->nbFiles)
1209         {
1210             memcpy( newfiles, files, pdb->nbFiles );
1211             memset( newfiles + pdb->nbFiles, 0xff, count - pdb->nbFiles );
1212         }
1213         else memcpy( newfiles, files, count );
1214 #ifdef WINELIB
1215         if (pdb->nbFiles > 20) GlobalFree32( (HGLOBAL32)pdb->fileHandlesPtr );
1216         pdb->fileHandlesPtr = (SEGPTR)newfiles;
1217 #else
1218         if (pdb->nbFiles > 20)
1219             GlobalFree16( GlobalHandle16( SELECTOROF(pdb->fileHandlesPtr) ));
1220         pdb->fileHandlesPtr = WIN16_GlobalLock16( newhandle );
1221 #endif  /* WINELIB */
1222         pdb->nbFiles = count;
1223     }
1224     return pdb->nbFiles;
1225 }
1226
1227
1228 /***********************************************************************
1229  *           FlushFileBuffers   (KERNEL32.133)
1230  */
1231 BOOL32 FlushFileBuffers( HFILE hFile )
1232 {
1233     DOS_FILE *file;
1234
1235     dprintf_file( stddeb, "FlushFileBuffers(%d)\n", hFile );
1236     if (!(file = FILE_GetFile( hFile ))) return FALSE;
1237     if (fsync( file->unix_handle ) != -1) return TRUE;
1238     FILE_SetDosError();
1239     return FALSE;
1240 }
1241
1242
1243 /***********************************************************************
1244  *           DeleteFile16   (KERNEL.146)
1245  */
1246 BOOL16 DeleteFile16( LPCSTR path )
1247 {
1248     return DeleteFile32A( path );
1249 }
1250
1251
1252 /***********************************************************************
1253  *           DeleteFile32A   (KERNEL32.71)
1254  */
1255 BOOL32 DeleteFile32A( LPCSTR path )
1256 {
1257     const char *unixName;
1258
1259     dprintf_file(stddeb, "DeleteFile: '%s'\n", path );
1260
1261     if ((unixName = DOSFS_IsDevice( path )) != NULL)
1262     {
1263         dprintf_file(stddeb, "DeleteFile: removing device '%s'!\n", unixName);
1264         DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
1265         return FALSE;
1266     }
1267
1268     if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return FALSE;
1269     if (unlink( unixName ) == -1)
1270     {
1271         FILE_SetDosError();
1272         return FALSE;
1273     }
1274     return TRUE;
1275 }
1276
1277
1278 /***********************************************************************
1279  *           DeleteFile32W   (KERNEL32.72)
1280  */
1281 BOOL32 DeleteFile32W( LPCWSTR path )
1282 {
1283     LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1284     BOOL32 ret = RemoveDirectory32A( xpath );
1285     HeapFree( GetProcessHeap(), 0, xpath );
1286     return ret;
1287 }
1288
1289
1290 /***********************************************************************
1291  *           CreateDirectory16   (KERNEL.144)
1292  */
1293 BOOL16 CreateDirectory16( LPCSTR path, LPVOID dummy )
1294 {
1295     dprintf_file( stddeb,"CreateDirectory16(%s,%p)\n", path, dummy );
1296     return (BOOL16)CreateDirectory32A( path, NULL );
1297 }
1298
1299
1300 /***********************************************************************
1301  *           CreateDirectory32A   (KERNEL32.39)
1302  */
1303 BOOL32 CreateDirectory32A( LPCSTR path, LPSECURITY_ATTRIBUTES lpsecattribs )
1304 {
1305     const char *unixName;
1306
1307     dprintf_file( stddeb, "CreateDirectory32A(%s,%p)\n", path, lpsecattribs );
1308     if ((unixName = DOSFS_IsDevice( path )) != NULL)
1309     {
1310         dprintf_file(stddeb, "CreateDirectory: device '%s'!\n", unixName);
1311         DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
1312         return FALSE;
1313     }
1314     if (!(unixName = DOSFS_GetUnixFileName( path, FALSE ))) return 0;
1315     if ((mkdir( unixName, 0777 ) == -1) && (errno != EEXIST))
1316     {
1317         FILE_SetDosError();
1318         return FALSE;
1319     }
1320     return TRUE;
1321 }
1322
1323
1324 /***********************************************************************
1325  *           CreateDirectory32W   (KERNEL32.42)
1326  */
1327 BOOL32 CreateDirectory32W( LPCWSTR path, LPSECURITY_ATTRIBUTES lpsecattribs )
1328 {
1329     LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1330     BOOL32 ret = CreateDirectory32A( xpath, lpsecattribs );
1331     HeapFree( GetProcessHeap(), 0, xpath );
1332     return ret;
1333 }
1334
1335 /***********************************************************************
1336  *           CreateDirectoryEx32A   (KERNEL32.40)
1337  */
1338 BOOL32 CreateDirectoryEx32A( LPCSTR template, LPCSTR path,
1339                              LPSECURITY_ATTRIBUTES lpsecattribs)
1340 {
1341     return CreateDirectory32A(path,lpsecattribs);
1342 }
1343
1344 /***********************************************************************
1345  *           CreateDirectoryEx32W   (KERNEL32.41)
1346  */
1347 BOOL32 CreateDirectoryEx32W( LPCWSTR template, LPCWSTR path,
1348                              LPSECURITY_ATTRIBUTES lpsecattribs)
1349 {
1350     return CreateDirectory32W(path,lpsecattribs);
1351 }
1352
1353 /***********************************************************************
1354  *           RemoveDirectory16   (KERNEL)
1355  */
1356 BOOL16 RemoveDirectory16( LPCSTR path )
1357 {
1358     return (BOOL16)RemoveDirectory32A( path );
1359 }
1360
1361
1362 /***********************************************************************
1363  *           RemoveDirectory32A   (KERNEL32.437)
1364  */
1365 BOOL32 RemoveDirectory32A( LPCSTR path )
1366 {
1367     const char *unixName;
1368
1369     dprintf_file(stddeb, "RemoveDirectory: '%s'\n", path );
1370
1371     if ((unixName = DOSFS_IsDevice( path )) != NULL)
1372     {
1373         dprintf_file(stddeb, "RemoveDirectory: device '%s'!\n", unixName);
1374         DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
1375         return FALSE;
1376     }
1377     if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return FALSE;
1378     if (rmdir( unixName ) == -1)
1379     {
1380         FILE_SetDosError();
1381         return FALSE;
1382     }
1383     return TRUE;
1384 }
1385
1386
1387 /***********************************************************************
1388  *           RemoveDirectory32W   (KERNEL32.438)
1389  */
1390 BOOL32 RemoveDirectory32W( LPCWSTR path )
1391 {
1392     LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
1393     BOOL32 ret = RemoveDirectory32A( xpath );
1394     HeapFree( GetProcessHeap(), 0, xpath );
1395     return ret;
1396 }
1397
1398
1399 /***********************************************************************
1400  *           FILE_SetFileType
1401  */
1402 BOOL32 FILE_SetFileType( HFILE hFile, DWORD type )
1403 {
1404     DOS_FILE *file = FILE_GetFile(hFile);
1405     if (!file) return FALSE;
1406     file->type = type;
1407     return TRUE;
1408 }
1409
1410
1411 /***********************************************************************
1412  *           GetFileType   (KERNEL32.222)
1413  */
1414 DWORD GetFileType( HFILE hFile )
1415 {
1416     DOS_FILE *file = FILE_GetFile(hFile);
1417     
1418     if (!file)
1419     {
1420         SetLastError( ERROR_INVALID_HANDLE );
1421         return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1422     }
1423     return file->type;
1424 }
1425
1426
1427 /***********************************************************************
1428  *              GetFileTime   (KERNEL32.221)
1429  */
1430 BOOL32 GetFileTime( HFILE hFile, FILETIME *lpCreationTime,
1431                     FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime )
1432 {
1433     DOS_FILE *file = FILE_GetFile(hFile);
1434     struct stat stbuf;
1435     
1436     if (!file) {
1437         SetLastError( ERROR_INVALID_HANDLE );
1438         return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1439     }
1440     dprintf_file(stddeb,"SetFileTime(%s,%p,%p,%p)\n",
1441         file->unix_name,
1442         lpCreationTime,
1443         lpLastAccessTime,
1444         lpLastWriteTime
1445     );
1446     if (-1==fstat(file->unix_handle,&stbuf)) {
1447         FILE_SetDosError();
1448         return FALSE;
1449     }
1450     if (lpLastWriteTime)
1451         DOSFS_UnixTimeToFileTime(stbuf.st_mtime,lpLastWriteTime);
1452     if (lpCreationTime)
1453         DOSFS_UnixTimeToFileTime(stbuf.st_ctime,lpCreationTime);
1454     if (lpLastAccessTime)
1455         DOSFS_UnixTimeToFileTime(stbuf.st_atime,lpLastAccessTime);
1456     return TRUE;
1457 }
1458
1459
1460 /***********************************************************************
1461  *              SetFileTime   (KERNEL32.493)
1462  */
1463 BOOL32 SetFileTime( HFILE hFile, FILETIME *lpCreationTime,
1464                     FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime )
1465 {
1466     DOS_FILE *file = FILE_GetFile(hFile);
1467     struct utimbuf utimbuf;
1468     
1469     if (!file) {
1470         SetLastError( ERROR_INVALID_HANDLE );
1471         return FILE_TYPE_UNKNOWN; /* FIXME: correct? */
1472     }
1473     dprintf_file(stddeb,"SetFileTime(%s,%p,%p,%p)\n",
1474         file->unix_name,
1475         lpCreationTime,
1476         lpLastAccessTime,
1477         lpLastWriteTime
1478     );
1479     if (lpLastAccessTime)
1480         utimbuf.actime  = DOSFS_FileTimeToUnixTime(lpLastAccessTime);
1481     else
1482         utimbuf.actime  = 0; /* FIXME */
1483     if (lpLastWriteTime)
1484         utimbuf.modtime = DOSFS_FileTimeToUnixTime(lpLastWriteTime);
1485     else
1486         utimbuf.modtime = 0; /* FIXME */
1487     if (-1==utime(file->unix_name,&utimbuf)) {
1488         FILE_SetDosError();
1489         return FALSE;
1490     }
1491     return TRUE;
1492 }