Added a few more info classes in NtQueryInformationFile.
[wine] / dlls / kernel / file.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 John Burton
5  * Copyright 1996 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * TODO:
22  *    Fix the CopyFileEx methods to implement the "extended" functionality.
23  *    Right now, they simply call the CopyFile method.
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <stdarg.h>
30
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33 #include "winerror.h"
34 #include "ntstatus.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winternl.h"
39 #include "wincon.h"
40 #include "wine/winbase16.h"
41 #include "kernel_private.h"
42
43 #include "wine/exception.h"
44 #include "excpt.h"
45 #include "wine/unicode.h"
46 #include "wine/debug.h"
47 #include "async.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(file);
50
51 HANDLE dos_handles[DOS_TABLE_SIZE];
52
53 /* info structure for FindFirstFile handle */
54 typedef struct
55 {
56     HANDLE           handle;      /* handle to directory */
57     CRITICAL_SECTION cs;          /* crit section protecting this structure */
58     UNICODE_STRING   mask;        /* file mask */
59     BOOL             is_root;     /* is directory the root of the drive? */
60     UINT             data_pos;    /* current position in dir data */
61     UINT             data_len;    /* length of dir data */
62     BYTE             data[8192];  /* directory data */
63 } FIND_FIRST_INFO;
64
65
66 static WINE_EXCEPTION_FILTER(page_fault)
67 {
68     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
69         return EXCEPTION_EXECUTE_HANDLER;
70     return EXCEPTION_CONTINUE_SEARCH;
71 }
72
73 /**************************************************************************
74  *                      Operations on file handles                        *
75  **************************************************************************/
76
77 /***********************************************************************
78  *           FILE_InitProcessDosHandles
79  *
80  * Allocates the default DOS handles for a process. Called either by
81  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
82  */
83 static void FILE_InitProcessDosHandles( void )
84 {
85     static BOOL init_done /* = FALSE */;
86     HANDLE cp = GetCurrentProcess();
87
88     if (init_done) return;
89     init_done = TRUE;
90     DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
91                     0, TRUE, DUPLICATE_SAME_ACCESS);
92     DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
93                     0, TRUE, DUPLICATE_SAME_ACCESS);
94     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
95                     0, TRUE, DUPLICATE_SAME_ACCESS);
96     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
97                     0, TRUE, DUPLICATE_SAME_ACCESS);
98     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
99                     0, TRUE, DUPLICATE_SAME_ACCESS);
100 }
101
102
103 /***********************************************************************
104  *              GetOverlappedResult     (KERNEL32.@)
105  *
106  * Check the result of an Asynchronous data transfer from a file.
107  *
108  * Parameters
109  *   HANDLE hFile                 [in] handle of file to check on
110  *   LPOVERLAPPED lpOverlapped    [in/out] pointer to overlapped
111  *   LPDWORD lpTransferred        [in/out] number of bytes transferred
112  *   BOOL bWait                   [in] wait for the transfer to complete ?
113  *
114  * RETURNS
115  *   TRUE on success
116  *   FALSE on failure
117  *
118  *  If successful (and relevant) lpTransferred will hold the number of
119  *   bytes transferred during the async operation.
120  *
121  * BUGS
122  *
123  * Currently only works for WaitCommEvent, ReadFile, WriteFile
124  *   with communications ports.
125  *
126  */
127 BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
128                                 LPDWORD lpTransferred, BOOL bWait)
129 {
130     DWORD r;
131
132     TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
133
134     if (lpOverlapped==NULL)
135     {
136         ERR("lpOverlapped was null\n");
137         return FALSE;
138     }
139     if (!lpOverlapped->hEvent)
140     {
141         ERR("lpOverlapped->hEvent was null\n");
142         return FALSE;
143     }
144
145     if ( bWait )
146     {
147         do {
148             TRACE("waiting on %p\n",lpOverlapped);
149             r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
150             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
151         } while (r==STATUS_USER_APC);
152     }
153     else if ( lpOverlapped->Internal == STATUS_PENDING )
154     {
155         /* Wait in order to give APCs a chance to run. */
156         /* This is cheating, so we must set the event again in case of success -
157            it may be a non-manual reset event. */
158         do {
159             TRACE("waiting on %p\n",lpOverlapped);
160             r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
161             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
162         } while (r==STATUS_USER_APC);
163         if ( r == WAIT_OBJECT_0 )
164             NtSetEvent ( lpOverlapped->hEvent, NULL );
165     }
166
167     if(lpTransferred)
168         *lpTransferred = lpOverlapped->InternalHigh;
169
170     switch ( lpOverlapped->Internal )
171     {
172     case STATUS_SUCCESS:
173         return TRUE;
174     case STATUS_PENDING:
175         SetLastError ( ERROR_IO_INCOMPLETE );
176         if ( bWait ) ERR ("PENDING status after waiting!\n");
177         return FALSE;
178     default:
179         SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
180         return FALSE;
181     }
182 }
183
184 /***********************************************************************
185  *             CancelIo                   (KERNEL32.@)
186  */
187 BOOL WINAPI CancelIo(HANDLE handle)
188 {
189     async_private *ovp,*t;
190
191     TRACE("handle = %p\n",handle);
192
193     for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
194     {
195         t = ovp->next;
196         if ( ovp->handle == handle )
197              cancel_async ( ovp );
198     }
199     SleepEx(1,TRUE);
200     return TRUE;
201 }
202
203 /***********************************************************************
204  *           _hread   (KERNEL32.@)
205  */
206 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
207 {
208     return _lread( hFile, buffer, count );
209 }
210
211
212 /***********************************************************************
213  *           _hwrite   (KERNEL32.@)
214  *
215  *      experimentation yields that _lwrite:
216  *              o truncates the file at the current position with
217  *                a 0 len write
218  *              o returns 0 on a 0 length write
219  *              o works with console handles
220  *
221  */
222 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
223 {
224     DWORD result;
225
226     TRACE("%d %p %ld\n", handle, buffer, count );
227
228     if (!count)
229     {
230         /* Expand or truncate at current position */
231         if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
232         return 0;
233     }
234     if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
235         return HFILE_ERROR;
236     return result;
237 }
238
239
240 /***********************************************************************
241  *           _lclose   (KERNEL32.@)
242  */
243 HFILE WINAPI _lclose( HFILE hFile )
244 {
245     TRACE("handle %d\n", hFile );
246     return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
247 }
248
249
250 /***********************************************************************
251  *           _lcreat   (KERNEL32.@)
252  */
253 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
254 {
255     /* Mask off all flags not explicitly allowed by the doc */
256     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
257     TRACE("%s %02x\n", path, attr );
258     return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
259                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
260                                CREATE_ALWAYS, attr, 0 );
261 }
262
263
264 /***********************************************************************
265  *           _lopen   (KERNEL32.@)
266  */
267 HFILE WINAPI _lopen( LPCSTR path, INT mode )
268 {
269     DWORD access, sharing;
270
271     TRACE("('%s',%04x)\n", path, mode );
272     FILE_ConvertOFMode( mode, &access, &sharing );
273     return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
274 }
275
276
277 /***********************************************************************
278  *           _lread   (KERNEL32.@)
279  */
280 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
281 {
282     DWORD result;
283     if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL ))
284         return HFILE_ERROR;
285     return result;
286 }
287
288
289 /***********************************************************************
290  *           _llseek   (KERNEL32.@)
291  */
292 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
293 {
294     return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
295 }
296
297
298 /***********************************************************************
299  *           _lwrite   (KERNEL32.@)
300  */
301 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
302 {
303     return (UINT)_hwrite( hFile, buffer, (LONG)count );
304 }
305
306
307 /***********************************************************************
308  *           FlushFileBuffers   (KERNEL32.@)
309  */
310 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
311 {
312     NTSTATUS            nts;
313     IO_STATUS_BLOCK     ioblk;
314
315     if (is_console_handle( hFile ))
316     {
317         /* this will fail (as expected) for an output handle */
318         /* FIXME: wait until FlushFileBuffers is moved to dll/kernel */
319         /* return FlushConsoleInputBuffer( hFile ); */
320         return TRUE;
321     }
322     nts = NtFlushBuffersFile( hFile, &ioblk );
323     if (nts != STATUS_SUCCESS)
324     {
325         SetLastError( RtlNtStatusToDosError( nts ) );
326         return FALSE;
327     }
328
329     return TRUE;
330 }
331
332
333 /***********************************************************************
334  *             GetFileInformationByHandle   (KERNEL32.@)
335  */
336 BOOL WINAPI GetFileInformationByHandle( HANDLE hFile, BY_HANDLE_FILE_INFORMATION *info )
337 {
338     FILE_ALL_INFORMATION all_info;
339     IO_STATUS_BLOCK io;
340     NTSTATUS status;
341
342     status = NtQueryInformationFile( hFile, &io, &all_info, sizeof(all_info), FileAllInformation );
343     if (status == STATUS_SUCCESS)
344     {
345         info->dwFileAttributes                = all_info.BasicInformation.FileAttributes;
346         info->ftCreationTime.dwHighDateTime   = all_info.BasicInformation.CreationTime.u.HighPart;
347         info->ftCreationTime.dwLowDateTime    = all_info.BasicInformation.CreationTime.u.LowPart;
348         info->ftLastAccessTime.dwHighDateTime = all_info.BasicInformation.LastAccessTime.u.HighPart;
349         info->ftLastAccessTime.dwLowDateTime  = all_info.BasicInformation.LastAccessTime.u.LowPart;
350         info->ftLastWriteTime.dwHighDateTime  = all_info.BasicInformation.LastWriteTime.u.HighPart;
351         info->ftLastWriteTime.dwLowDateTime   = all_info.BasicInformation.LastWriteTime.u.LowPart;
352         info->dwVolumeSerialNumber            = 0;  /* FIXME */
353         info->nFileSizeHigh                   = all_info.StandardInformation.EndOfFile.u.HighPart;
354         info->nFileSizeLow                    = all_info.StandardInformation.EndOfFile.u.LowPart;
355         info->nNumberOfLinks                  = all_info.StandardInformation.NumberOfLinks;
356         info->nFileIndexHigh                  = all_info.InternalInformation.IndexNumber.u.HighPart;
357         info->nFileIndexLow                   = all_info.InternalInformation.IndexNumber.u.LowPart;
358         return TRUE;
359     }
360     SetLastError( RtlNtStatusToDosError(status) );
361     return FALSE;
362 }
363
364
365 /***********************************************************************
366  *           GetFileSize   (KERNEL32.@)
367  */
368 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
369 {
370     LARGE_INTEGER size;
371     if (!GetFileSizeEx( hFile, &size )) return INVALID_FILE_SIZE;
372     if (filesizehigh) *filesizehigh = size.u.HighPart;
373     if (size.u.LowPart == INVALID_FILE_SIZE) SetLastError(0);
374     return size.u.LowPart;
375 }
376
377
378 /***********************************************************************
379  *           GetFileSizeEx   (KERNEL32.@)
380  */
381 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
382 {
383     FILE_END_OF_FILE_INFORMATION info;
384     IO_STATUS_BLOCK io;
385     NTSTATUS status;
386
387     status = NtQueryInformationFile( hFile, &io, &info, sizeof(info), FileEndOfFileInformation );
388     if (status == STATUS_SUCCESS)
389     {
390         *lpFileSize = info.EndOfFile;
391         return TRUE;
392     }
393     SetLastError( RtlNtStatusToDosError(status) );
394     return FALSE;
395 }
396
397
398 /***********************************************************************
399  *           GetFileTime   (KERNEL32.@)
400  */
401 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
402                          FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime )
403 {
404     FILE_BASIC_INFORMATION info;
405     IO_STATUS_BLOCK io;
406     NTSTATUS status;
407
408     status = NtQueryInformationFile( hFile, &io, &info, sizeof(info), FileBasicInformation );
409     if (status == STATUS_SUCCESS)
410     {
411         if (lpCreationTime)
412         {
413             lpCreationTime->dwHighDateTime = info.CreationTime.u.HighPart;
414             lpCreationTime->dwLowDateTime  = info.CreationTime.u.LowPart;
415         }
416         if (lpLastAccessTime)
417         {
418             lpLastAccessTime->dwHighDateTime = info.LastAccessTime.u.HighPart;
419             lpLastAccessTime->dwLowDateTime  = info.LastAccessTime.u.LowPart;
420         }
421         if (lpLastWriteTime)
422         {
423             lpLastWriteTime->dwHighDateTime = info.LastWriteTime.u.HighPart;
424             lpLastWriteTime->dwLowDateTime  = info.LastWriteTime.u.LowPart;
425         }
426         return TRUE;
427     }
428     SetLastError( RtlNtStatusToDosError(status) );
429     return FALSE;
430 }
431
432
433 /***********************************************************************
434  *              SetFileTime   (KERNEL32.@)
435  */
436 BOOL WINAPI SetFileTime( HANDLE hFile, const FILETIME *ctime,
437                          const FILETIME *atime, const FILETIME *mtime )
438 {
439     FILE_BASIC_INFORMATION info;
440     IO_STATUS_BLOCK io;
441     NTSTATUS status;
442
443     memset( &info, 0, sizeof(info) );
444     if (ctime)
445     {
446         info.CreationTime.u.HighPart = ctime->dwHighDateTime;
447         info.CreationTime.u.LowPart  = ctime->dwLowDateTime;
448     }
449     if (atime)
450     {
451         info.LastAccessTime.u.HighPart = atime->dwHighDateTime;
452         info.LastAccessTime.u.LowPart  = atime->dwLowDateTime;
453     }
454     if (mtime)
455     {
456         info.LastWriteTime.u.HighPart = mtime->dwHighDateTime;
457         info.LastWriteTime.u.LowPart  = mtime->dwLowDateTime;
458     }
459
460     status = NtSetInformationFile( hFile, &io, &info, sizeof(info), FileBasicInformation );
461     if (status == STATUS_SUCCESS) return TRUE;
462     SetLastError( RtlNtStatusToDosError(status) );
463     return FALSE;
464 }
465
466
467 /**************************************************************************
468  *           LockFile   (KERNEL32.@)
469  */
470 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
471                       DWORD count_low, DWORD count_high )
472 {
473     NTSTATUS            status;
474     LARGE_INTEGER       count, offset;
475
476     TRACE( "%p %lx%08lx %lx%08lx\n", 
477            hFile, offset_high, offset_low, count_high, count_low );
478
479     count.u.LowPart = count_low;
480     count.u.HighPart = count_high;
481     offset.u.LowPart = offset_low;
482     offset.u.HighPart = offset_high;
483
484     status = NtLockFile( hFile, 0, NULL, NULL, 
485                          NULL, &offset, &count, NULL, TRUE, TRUE );
486     
487     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
488     return !status;
489 }
490
491
492 /**************************************************************************
493  * LockFileEx [KERNEL32.@]
494  *
495  * Locks a byte range within an open file for shared or exclusive access.
496  *
497  * RETURNS
498  *   success: TRUE
499  *   failure: FALSE
500  *
501  * NOTES
502  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
503  */
504 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
505                         DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
506 {
507     NTSTATUS status;
508     LARGE_INTEGER count, offset;
509
510     if (reserved)
511     {
512         SetLastError( ERROR_INVALID_PARAMETER );
513         return FALSE;
514     }
515
516     TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
517            hFile, overlapped->OffsetHigh, overlapped->Offset, 
518            count_high, count_low, flags );
519
520     count.u.LowPart = count_low;
521     count.u.HighPart = count_high;
522     offset.u.LowPart = overlapped->Offset;
523     offset.u.HighPart = overlapped->OffsetHigh;
524
525     status = NtLockFile( hFile, overlapped->hEvent, NULL, NULL, 
526                          NULL, &offset, &count, NULL, 
527                          flags & LOCKFILE_FAIL_IMMEDIATELY,
528                          flags & LOCKFILE_EXCLUSIVE_LOCK );
529     
530     if (status) SetLastError( RtlNtStatusToDosError(status) );
531     return !status;
532 }
533
534
535 /**************************************************************************
536  *           UnlockFile   (KERNEL32.@)
537  */
538 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
539                         DWORD count_low, DWORD count_high )
540 {
541     NTSTATUS    status;
542     LARGE_INTEGER count, offset;
543
544     count.u.LowPart = count_low;
545     count.u.HighPart = count_high;
546     offset.u.LowPart = offset_low;
547     offset.u.HighPart = offset_high;
548
549     status = NtUnlockFile( hFile, NULL, &offset, &count, NULL);
550     if (status) SetLastError( RtlNtStatusToDosError(status) );
551     return !status;
552 }
553
554
555 /**************************************************************************
556  *           UnlockFileEx   (KERNEL32.@)
557  */
558 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
559                           LPOVERLAPPED overlapped )
560 {
561     if (reserved)
562     {
563         SetLastError( ERROR_INVALID_PARAMETER );
564         return FALSE;
565     }
566     if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n");
567
568     return UnlockFile( hFile, overlapped->Offset, overlapped->OffsetHigh, count_low, count_high );
569 }
570
571
572 /***********************************************************************
573  *           Win32HandleToDosFileHandle   (KERNEL32.21)
574  *
575  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
576  * longer valid after this function (even on failure).
577  *
578  * Note: this is not exactly right, since on Win95 the Win32 handles
579  *       are on top of DOS handles and we do it the other way
580  *       around. Should be good enough though.
581  */
582 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
583 {
584     int i;
585
586     if (!handle || (handle == INVALID_HANDLE_VALUE))
587         return HFILE_ERROR;
588
589     FILE_InitProcessDosHandles();
590     for (i = 0; i < DOS_TABLE_SIZE; i++)
591         if (!dos_handles[i])
592         {
593             dos_handles[i] = handle;
594             TRACE("Got %d for h32 %p\n", i, handle );
595             return (HFILE)i;
596         }
597     CloseHandle( handle );
598     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
599     return HFILE_ERROR;
600 }
601
602
603 /***********************************************************************
604  *           DosFileHandleToWin32Handle   (KERNEL32.20)
605  *
606  * Return the Win32 handle for a DOS handle.
607  *
608  * Note: this is not exactly right, since on Win95 the Win32 handles
609  *       are on top of DOS handles and we do it the other way
610  *       around. Should be good enough though.
611  */
612 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
613 {
614     HFILE16 hfile = (HFILE16)handle;
615     if (hfile < 5) FILE_InitProcessDosHandles();
616     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
617     {
618         SetLastError( ERROR_INVALID_HANDLE );
619         return INVALID_HANDLE_VALUE;
620     }
621     return dos_handles[hfile];
622 }
623
624
625 /***********************************************************************
626  *           DisposeLZ32Handle   (KERNEL32.22)
627  *
628  * Note: this is not entirely correct, we should only close the
629  *       32-bit handle and not the 16-bit one, but we cannot do
630  *       this because of the way our DOS handles are implemented.
631  *       It shouldn't break anything though.
632  */
633 void WINAPI DisposeLZ32Handle( HANDLE handle )
634 {
635     int i;
636
637     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
638
639     for (i = 5; i < DOS_TABLE_SIZE; i++)
640         if (dos_handles[i] == handle)
641         {
642             dos_handles[i] = 0;
643             CloseHandle( handle );
644             break;
645         }
646 }
647
648 /**************************************************************************
649  *                      Operations on file names                          *
650  **************************************************************************/
651
652 /***********************************************************************
653  *           DeleteFileW   (KERNEL32.@)
654  */
655 BOOL WINAPI DeleteFileW( LPCWSTR path )
656 {
657     HANDLE hFile;
658
659     TRACE("%s\n", debugstr_w(path) );
660
661     hFile = CreateFileW( path, GENERIC_READ | GENERIC_WRITE,
662                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
663                          NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0 );
664     if (hFile == INVALID_HANDLE_VALUE) return FALSE;
665
666     CloseHandle(hFile);  /* last close will delete the file */
667     return TRUE;
668 }
669
670
671 /***********************************************************************
672  *           DeleteFileA   (KERNEL32.@)
673  */
674 BOOL WINAPI DeleteFileA( LPCSTR path )
675 {
676     UNICODE_STRING pathW;
677     BOOL ret = FALSE;
678
679     if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
680     {
681         ret = DeleteFileW(pathW.Buffer);
682         RtlFreeUnicodeString(&pathW);
683     }
684     else
685         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
686     return ret;
687 }
688
689
690 /**************************************************************************
691  *           ReplaceFileW   (KERNEL32.@)
692  *           ReplaceFile    (KERNEL32.@)
693  */
694 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
695                          LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
696                          LPVOID lpExclude, LPVOID lpReserved)
697 {
698     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
699                                           debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
700     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
701     return FALSE;
702 }
703
704
705 /**************************************************************************
706  *           ReplaceFileA (KERNEL32.@)
707  */
708 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
709                          LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
710                          LPVOID lpExclude, LPVOID lpReserved)
711 {
712     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
713                                           lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
714     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
715     return FALSE;
716 }
717
718
719 /*************************************************************************
720  *           FindFirstFileExW  (KERNEL32.@)
721  */
722 HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
723                                 LPVOID data, FINDEX_SEARCH_OPS search_op,
724                                 LPVOID filter, DWORD flags)
725 {
726     WCHAR *mask, *p;
727     FIND_FIRST_INFO *info = NULL;
728     UNICODE_STRING nt_name;
729     OBJECT_ATTRIBUTES attr;
730     IO_STATUS_BLOCK io;
731     NTSTATUS status;
732
733     if ((search_op != FindExSearchNameMatch) || (flags != 0))
734     {
735         FIXME("options not implemented 0x%08x 0x%08lx\n", search_op, flags );
736         return INVALID_HANDLE_VALUE;
737     }
738     if (level != FindExInfoStandard)
739     {
740         FIXME("info level %d not implemented\n", level );
741         return INVALID_HANDLE_VALUE;
742     }
743
744     if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, &mask, NULL ))
745     {
746         SetLastError( ERROR_PATH_NOT_FOUND );
747         return INVALID_HANDLE_VALUE;
748     }
749
750     if (!mask || !*mask)
751     {
752         SetLastError( ERROR_FILE_NOT_FOUND );
753         goto error;
754     }
755
756     if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info))))
757     {
758         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
759         goto error;
760     }
761
762     if (!RtlCreateUnicodeString( &info->mask, mask ))
763     {
764         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
765         goto error;
766     }
767
768     /* truncate dir name before mask */
769     *mask = 0;
770     nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
771
772     /* check if path is the root of the drive */
773     info->is_root = FALSE;
774     p = nt_name.Buffer + 4;  /* skip \??\ prefix */
775     if (p[0] && p[1] == ':')
776     {
777         p += 2;
778         while (*p == '\\') p++;
779         info->is_root = (*p == 0);
780     }
781
782     attr.Length = sizeof(attr);
783     attr.RootDirectory = 0;
784     attr.Attributes = OBJ_CASE_INSENSITIVE;
785     attr.ObjectName = &nt_name;
786     attr.SecurityDescriptor = NULL;
787     attr.SecurityQualityOfService = NULL;
788
789     status = NtOpenFile( &info->handle, GENERIC_READ, &attr, &io,
790                          FILE_SHARE_READ | FILE_SHARE_WRITE,
791                          FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
792
793     if (status != STATUS_SUCCESS)
794     {
795         RtlFreeUnicodeString( &info->mask );
796         SetLastError( RtlNtStatusToDosError(status) );
797         goto error;
798     }
799     RtlFreeUnicodeString( &nt_name );
800
801     RtlInitializeCriticalSection( &info->cs );
802     info->data_pos = 0;
803     info->data_len = 0;
804
805     if (!FindNextFileW( (HANDLE)info, data ))
806     {
807         TRACE( "%s not found\n", debugstr_w(filename) );
808         FindClose( (HANDLE)info );
809         SetLastError( ERROR_FILE_NOT_FOUND );
810         return INVALID_HANDLE_VALUE;
811     }
812     return (HANDLE)info;
813
814 error:
815     if (info) HeapFree( GetProcessHeap(), 0, info );
816     RtlFreeUnicodeString( &nt_name );
817     return INVALID_HANDLE_VALUE;
818 }
819
820
821 /*************************************************************************
822  *           FindNextFileW   (KERNEL32.@)
823  */
824 BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
825 {
826     FIND_FIRST_INFO *info;
827     FILE_BOTH_DIR_INFORMATION *dir_info;
828     BOOL ret = FALSE;
829
830     if (handle == INVALID_HANDLE_VALUE)
831     {
832         SetLastError( ERROR_INVALID_HANDLE );
833         return ret;
834     }
835     info = (FIND_FIRST_INFO *)handle;
836
837     RtlEnterCriticalSection( &info->cs );
838
839     for (;;)
840     {
841         if (info->data_pos >= info->data_len)  /* need to read some more data */
842         {
843             IO_STATUS_BLOCK io;
844
845             NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
846                                   FileBothDirectoryInformation, FALSE, &info->mask, FALSE );
847             if (io.u.Status)
848             {
849                 SetLastError( RtlNtStatusToDosError( io.u.Status ) );
850                 break;
851             }
852             info->data_len = io.Information;
853             info->data_pos = 0;
854         }
855
856         dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
857
858         if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset;
859         else info->data_pos = info->data_len;
860
861         /* don't return '.' and '..' in the root of the drive */
862         if (info->is_root)
863         {
864             if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue;
865             if (dir_info->FileNameLength == 2 * sizeof(WCHAR) &&
866                 dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue;
867         }
868
869         data->dwFileAttributes = dir_info->FileAttributes;
870         data->ftCreationTime   = *(FILETIME *)&dir_info->CreationTime;
871         data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
872         data->ftLastWriteTime  = *(FILETIME *)&dir_info->LastWriteTime;
873         data->nFileSizeHigh    = dir_info->EndOfFile.QuadPart >> 32;
874         data->nFileSizeLow     = (DWORD)dir_info->EndOfFile.QuadPart;
875         data->dwReserved0      = 0;
876         data->dwReserved1      = 0;
877
878         memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
879         data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
880         memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
881         data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0;
882
883         TRACE("returning %s (%s)\n",
884               debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) );
885
886         ret = TRUE;
887         break;
888     }
889
890     RtlLeaveCriticalSection( &info->cs );
891     return ret;
892 }
893
894
895 /*************************************************************************
896  *           FindClose   (KERNEL32.@)
897  */
898 BOOL WINAPI FindClose( HANDLE handle )
899 {
900     FIND_FIRST_INFO *info = (FIND_FIRST_INFO *)handle;
901
902     if (!handle || handle == INVALID_HANDLE_VALUE) goto error;
903
904     __TRY
905     {
906         RtlEnterCriticalSection( &info->cs );
907         if (info->handle) CloseHandle( info->handle );
908         info->handle = 0;
909         RtlFreeUnicodeString( &info->mask );
910         info->mask.Buffer = NULL;
911         info->data_pos = 0;
912         info->data_len = 0;
913     }
914     __EXCEPT(page_fault)
915     {
916         WARN("Illegal handle %p\n", handle);
917         SetLastError( ERROR_INVALID_HANDLE );
918         return FALSE;
919     }
920     __ENDTRY
921
922     RtlLeaveCriticalSection( &info->cs );
923     RtlDeleteCriticalSection( &info->cs );
924     HeapFree(GetProcessHeap(), 0, info);
925     return TRUE;
926
927  error:
928     SetLastError( ERROR_INVALID_HANDLE );
929     return FALSE;
930 }
931
932
933 /*************************************************************************
934  *           FindFirstFileA   (KERNEL32.@)
935  */
936 HANDLE WINAPI FindFirstFileA( LPCSTR lpFileName, WIN32_FIND_DATAA *lpFindData )
937 {
938     return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
939                             FindExSearchNameMatch, NULL, 0);
940 }
941
942 /*************************************************************************
943  *           FindFirstFileExA   (KERNEL32.@)
944  */
945 HANDLE WINAPI FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId,
946                                 LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp,
947                                 LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
948 {
949     HANDLE handle;
950     WIN32_FIND_DATAA *dataA;
951     WIN32_FIND_DATAW dataW;
952     UNICODE_STRING pathW;
953
954     if (!lpFileName)
955     {
956         SetLastError(ERROR_PATH_NOT_FOUND);
957         return INVALID_HANDLE_VALUE;
958     }
959
960     if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
961     {
962         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
963         return INVALID_HANDLE_VALUE;
964     }
965
966     handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
967     RtlFreeUnicodeString(&pathW);
968     if (handle == INVALID_HANDLE_VALUE) return handle;
969
970     dataA = (WIN32_FIND_DATAA *) lpFindFileData;
971     dataA->dwFileAttributes = dataW.dwFileAttributes;
972     dataA->ftCreationTime   = dataW.ftCreationTime;
973     dataA->ftLastAccessTime = dataW.ftLastAccessTime;
974     dataA->ftLastWriteTime  = dataW.ftLastWriteTime;
975     dataA->nFileSizeHigh    = dataW.nFileSizeHigh;
976     dataA->nFileSizeLow     = dataW.nFileSizeLow;
977     WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
978                          dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
979     WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
980                          dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
981     return handle;
982 }
983
984
985 /*************************************************************************
986  *           FindFirstFileW   (KERNEL32.@)
987  */
988 HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
989 {
990     return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
991                             FindExSearchNameMatch, NULL, 0);
992 }
993
994
995 /*************************************************************************
996  *           FindNextFileA   (KERNEL32.@)
997  */
998 BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
999 {
1000     WIN32_FIND_DATAW dataW;
1001
1002     if (!FindNextFileW( handle, &dataW )) return FALSE;
1003     data->dwFileAttributes = dataW.dwFileAttributes;
1004     data->ftCreationTime   = dataW.ftCreationTime;
1005     data->ftLastAccessTime = dataW.ftLastAccessTime;
1006     data->ftLastWriteTime  = dataW.ftLastWriteTime;
1007     data->nFileSizeHigh    = dataW.nFileSizeHigh;
1008     data->nFileSizeLow     = dataW.nFileSizeLow;
1009     WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
1010                          data->cFileName, sizeof(data->cFileName), NULL, NULL );
1011     WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
1012                          data->cAlternateFileName,
1013                          sizeof(data->cAlternateFileName), NULL, NULL );
1014     return TRUE;
1015 }
1016
1017
1018 /**************************************************************************
1019  *           GetFileAttributesW   (KERNEL32.@)
1020  */
1021 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
1022 {
1023     FILE_BASIC_INFORMATION info;
1024     UNICODE_STRING nt_name;
1025     OBJECT_ATTRIBUTES attr;
1026     NTSTATUS status;
1027
1028     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1029     {
1030         SetLastError( ERROR_PATH_NOT_FOUND );
1031         return INVALID_FILE_ATTRIBUTES;
1032     }
1033
1034     attr.Length = sizeof(attr);
1035     attr.RootDirectory = 0;
1036     attr.Attributes = OBJ_CASE_INSENSITIVE;
1037     attr.ObjectName = &nt_name;
1038     attr.SecurityDescriptor = NULL;
1039     attr.SecurityQualityOfService = NULL;
1040
1041     status = NtQueryAttributesFile( &attr, &info );
1042     RtlFreeUnicodeString( &nt_name );
1043
1044     if (status == STATUS_SUCCESS) return info.FileAttributes;
1045
1046     /* NtQueryAttributesFile fails on devices, but GetFileAttributesW succeeds */
1047     if (RtlIsDosDeviceName_U( name )) return FILE_ATTRIBUTE_ARCHIVE;
1048
1049     SetLastError( RtlNtStatusToDosError(status) );
1050     return INVALID_FILE_ATTRIBUTES;
1051 }
1052
1053
1054 /**************************************************************************
1055  *           GetFileAttributesA   (KERNEL32.@)
1056  */
1057 DWORD WINAPI GetFileAttributesA( LPCSTR name )
1058 {
1059     UNICODE_STRING nameW;
1060     DWORD ret = INVALID_FILE_ATTRIBUTES;
1061
1062     if (!name)
1063     {
1064         SetLastError( ERROR_INVALID_PARAMETER );
1065         return INVALID_FILE_ATTRIBUTES;
1066     }
1067
1068     if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
1069     {
1070         ret = GetFileAttributesW(nameW.Buffer);
1071         RtlFreeUnicodeString(&nameW);
1072     }
1073     else
1074         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1075     return ret;
1076 }
1077
1078
1079 /**************************************************************************
1080  *              SetFileAttributesW      (KERNEL32.@)
1081  */
1082 BOOL WINAPI SetFileAttributesW( LPCWSTR name, DWORD attributes )
1083 {
1084     UNICODE_STRING nt_name;
1085     OBJECT_ATTRIBUTES attr;
1086     IO_STATUS_BLOCK io;
1087     NTSTATUS status;
1088     HANDLE handle;
1089
1090     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1091     {
1092         SetLastError( ERROR_PATH_NOT_FOUND );
1093         return FALSE;
1094     }
1095
1096     attr.Length = sizeof(attr);
1097     attr.RootDirectory = 0;
1098     attr.Attributes = OBJ_CASE_INSENSITIVE;
1099     attr.ObjectName = &nt_name;
1100     attr.SecurityDescriptor = NULL;
1101     attr.SecurityQualityOfService = NULL;
1102
1103     status = NtOpenFile( &handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT );
1104     RtlFreeUnicodeString( &nt_name );
1105
1106     if (status == STATUS_SUCCESS)
1107     {
1108         FILE_BASIC_INFORMATION info;
1109
1110         memset( &info, 0, sizeof(info) );
1111         info.FileAttributes = attributes | FILE_ATTRIBUTE_NORMAL;  /* make sure it's not zero */
1112         status = NtSetInformationFile( handle, &io, &info, sizeof(info), FileBasicInformation );
1113         NtClose( handle );
1114     }
1115
1116     if (status == STATUS_SUCCESS) return TRUE;
1117     SetLastError( RtlNtStatusToDosError(status) );
1118     return FALSE;
1119 }
1120
1121
1122 /**************************************************************************
1123  *              SetFileAttributesA      (KERNEL32.@)
1124  */
1125 BOOL WINAPI SetFileAttributesA( LPCSTR name, DWORD attributes )
1126 {
1127     UNICODE_STRING filenameW;
1128     BOOL ret = FALSE;
1129
1130     if (!name)
1131     {
1132         SetLastError( ERROR_INVALID_PARAMETER );
1133         return FALSE;
1134     }
1135
1136     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, name))
1137     {
1138         ret = SetFileAttributesW(filenameW.Buffer, attributes);
1139         RtlFreeUnicodeString(&filenameW);
1140     }
1141     else
1142         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1143     return ret;
1144 }
1145
1146
1147 /**************************************************************************
1148  *           GetFileAttributesExW   (KERNEL32.@)
1149  */
1150 BOOL WINAPI GetFileAttributesExW( LPCWSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr )
1151 {
1152     FILE_NETWORK_OPEN_INFORMATION info;
1153     WIN32_FILE_ATTRIBUTE_DATA *data = ptr;
1154     UNICODE_STRING nt_name;
1155     OBJECT_ATTRIBUTES attr;
1156     NTSTATUS status;
1157
1158     if (level != GetFileExInfoStandard)
1159     {
1160         SetLastError( ERROR_INVALID_PARAMETER );
1161         return FALSE;
1162     }
1163
1164     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1165     {
1166         SetLastError( ERROR_PATH_NOT_FOUND );
1167         return FALSE;
1168     }
1169
1170     attr.Length = sizeof(attr);
1171     attr.RootDirectory = 0;
1172     attr.Attributes = OBJ_CASE_INSENSITIVE;
1173     attr.ObjectName = &nt_name;
1174     attr.SecurityDescriptor = NULL;
1175     attr.SecurityQualityOfService = NULL;
1176
1177     status = NtQueryFullAttributesFile( &attr, &info );
1178     RtlFreeUnicodeString( &nt_name );
1179
1180     if (status != STATUS_SUCCESS)
1181     {
1182         SetLastError( RtlNtStatusToDosError(status) );
1183         return FALSE;
1184     }
1185
1186     data->dwFileAttributes = info.FileAttributes;
1187     data->ftCreationTime.dwLowDateTime    = info.CreationTime.u.LowPart;
1188     data->ftCreationTime.dwHighDateTime   = info.CreationTime.u.HighPart;
1189     data->ftLastAccessTime.dwLowDateTime  = info.LastAccessTime.u.LowPart;
1190     data->ftLastAccessTime.dwHighDateTime = info.LastAccessTime.u.HighPart;
1191     data->ftLastWriteTime.dwLowDateTime   = info.LastWriteTime.u.LowPart;
1192     data->ftLastWriteTime.dwHighDateTime  = info.LastWriteTime.u.HighPart;
1193     data->nFileSizeLow                    = info.EndOfFile.u.LowPart;
1194     data->nFileSizeHigh                   = info.EndOfFile.u.HighPart;
1195     return TRUE;
1196 }
1197
1198
1199 /**************************************************************************
1200  *           GetFileAttributesExA   (KERNEL32.@)
1201  */
1202 BOOL WINAPI GetFileAttributesExA( LPCSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr )
1203 {
1204     UNICODE_STRING filenameW;
1205     BOOL ret = FALSE;
1206
1207     if (!name)
1208     {
1209         SetLastError(ERROR_INVALID_PARAMETER);
1210         return FALSE;
1211     }
1212
1213     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, name))
1214     {
1215         ret = GetFileAttributesExW(filenameW.Buffer, level, ptr);
1216         RtlFreeUnicodeString(&filenameW);
1217     }
1218     else
1219         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1220     return ret;
1221 }
1222
1223
1224 /******************************************************************************
1225  *           GetCompressedFileSizeW   (KERNEL32.@)
1226  *
1227  * RETURNS
1228  *    Success: Low-order doubleword of number of bytes
1229  *    Failure: INVALID_FILE_SIZE
1230  */
1231 DWORD WINAPI GetCompressedFileSizeW(
1232     LPCWSTR name,       /* [in]  Pointer to name of file */
1233     LPDWORD size_high ) /* [out] Receives high-order doubleword of size */
1234 {
1235     UNICODE_STRING nt_name;
1236     OBJECT_ATTRIBUTES attr;
1237     IO_STATUS_BLOCK io;
1238     NTSTATUS status;
1239     HANDLE handle;
1240     DWORD ret = INVALID_FILE_SIZE;
1241
1242     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1243     {
1244         SetLastError( ERROR_PATH_NOT_FOUND );
1245         return INVALID_FILE_SIZE;
1246     }
1247
1248     attr.Length = sizeof(attr);
1249     attr.RootDirectory = 0;
1250     attr.Attributes = OBJ_CASE_INSENSITIVE;
1251     attr.ObjectName = &nt_name;
1252     attr.SecurityDescriptor = NULL;
1253     attr.SecurityQualityOfService = NULL;
1254
1255     status = NtOpenFile( &handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT );
1256     RtlFreeUnicodeString( &nt_name );
1257
1258     if (status == STATUS_SUCCESS)
1259     {
1260         /* we don't support compressed files, simply return the file size */
1261         ret = GetFileSize( handle, size_high );
1262         NtClose( handle );
1263     }
1264     else SetLastError( RtlNtStatusToDosError(status) );
1265
1266     return ret;
1267 }
1268
1269
1270 /******************************************************************************
1271  *           GetCompressedFileSizeA   (KERNEL32.@)
1272  */
1273 DWORD WINAPI GetCompressedFileSizeA( LPCSTR name, LPDWORD size_high )
1274 {
1275     UNICODE_STRING filenameW;
1276     DWORD ret;
1277
1278     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, name))
1279     {
1280         ret = GetCompressedFileSizeW(filenameW.Buffer, size_high);
1281         RtlFreeUnicodeString(&filenameW);
1282     }
1283     else
1284     {
1285         ret = INVALID_FILE_SIZE;
1286         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1287     }
1288     return ret;
1289 }
1290
1291
1292 /***********************************************************************
1293  *           OpenFile   (KERNEL32.@)
1294  */
1295 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1296 {
1297     HANDLE handle;
1298     FILETIME filetime;
1299     WORD filedatetime[2];
1300
1301     if (!ofs) return HFILE_ERROR;
1302
1303     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1304           ((mode & 0x3 )==OF_READ)?"OF_READ":
1305           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1306           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1307           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1308           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1309           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1310           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1311           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1312           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1313           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1314           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1315           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1316           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1317           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1318           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1319           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1320           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1321         );
1322
1323
1324     ofs->cBytes = sizeof(OFSTRUCT);
1325     ofs->nErrCode = 0;
1326     if (mode & OF_REOPEN) name = ofs->szPathName;
1327
1328     if (!name) return HFILE_ERROR;
1329
1330     TRACE("%s %04x\n", name, mode );
1331
1332     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1333        Are there any cases where getting the path here is wrong?
1334        Uwe Bonnes 1997 Apr 2 */
1335     if (!GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL )) goto error;
1336
1337     /* OF_PARSE simply fills the structure */
1338
1339     if (mode & OF_PARSE)
1340     {
1341         ofs->fFixedDisk = (GetDriveTypeA( ofs->szPathName ) != DRIVE_REMOVABLE);
1342         TRACE("(%s): OF_PARSE, res = '%s'\n", name, ofs->szPathName );
1343         return 0;
1344     }
1345
1346     /* OF_CREATE is completely different from all other options, so
1347        handle it first */
1348
1349     if (mode & OF_CREATE)
1350     {
1351         DWORD access, sharing;
1352         FILE_ConvertOFMode( mode, &access, &sharing );
1353         if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1354                                    sharing, NULL, CREATE_ALWAYS,
1355                                    FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1356             goto error;
1357     }
1358     else
1359     {
1360         /* Now look for the file */
1361
1362         if (!SearchPathA( NULL, name, NULL, sizeof(ofs->szPathName), ofs->szPathName, NULL ))
1363             goto error;
1364
1365         TRACE("found %s\n", debugstr_a(ofs->szPathName) );
1366
1367         if (mode & OF_DELETE)
1368         {
1369             if (!DeleteFileA( ofs->szPathName )) goto error;
1370             TRACE("(%s): OF_DELETE return = OK\n", name);
1371             return TRUE;
1372         }
1373
1374         handle = (HANDLE)_lopen( ofs->szPathName, mode );
1375         if (handle == INVALID_HANDLE_VALUE) goto error;
1376
1377         GetFileTime( handle, NULL, NULL, &filetime );
1378         FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1379         if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1380         {
1381             if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1382             {
1383                 CloseHandle( handle );
1384                 WARN("(%s): OF_VERIFY failed\n", name );
1385                 /* FIXME: what error here? */
1386                 SetLastError( ERROR_FILE_NOT_FOUND );
1387                 goto error;
1388             }
1389         }
1390         ofs->Reserved1 = filedatetime[0];
1391         ofs->Reserved2 = filedatetime[1];
1392     }
1393     TRACE("(%s): OK, return = %p\n", name, handle );
1394     if (mode & OF_EXIST)  /* Return TRUE instead of a handle */
1395     {
1396         CloseHandle( handle );
1397         return TRUE;
1398     }
1399     else return (HFILE)handle;
1400
1401 error:  /* We get here if there was an error opening the file */
1402     ofs->nErrCode = GetLastError();
1403     WARN("(%s): return = HFILE_ERROR error= %d\n", name,ofs->nErrCode );
1404     return HFILE_ERROR;
1405 }