Assorted spelling fixes.
[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  *           GetFileSize   (KERNEL32.@)
335  */
336 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
337 {
338     BY_HANDLE_FILE_INFORMATION info;
339     if (!GetFileInformationByHandle( hFile, &info )) return -1;
340     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
341     return info.nFileSizeLow;
342 }
343
344
345 /***********************************************************************
346  *           GetFileSizeEx   (KERNEL32.@)
347  */
348 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
349 {
350     BY_HANDLE_FILE_INFORMATION info;
351
352     if (!lpFileSize)
353     {
354         SetLastError( ERROR_INVALID_PARAMETER );
355         return FALSE;
356     }
357
358     if (!GetFileInformationByHandle( hFile, &info ))
359     {
360         return FALSE;
361     }
362
363     lpFileSize->u.LowPart = info.nFileSizeLow;
364     lpFileSize->u.HighPart = info.nFileSizeHigh;
365
366     return TRUE;
367 }
368
369
370 /***********************************************************************
371  *              SetFileTime   (KERNEL32.@)
372  */
373 BOOL WINAPI SetFileTime( HANDLE hFile, const FILETIME *ctime,
374                          const FILETIME *atime, const FILETIME *mtime )
375 {
376     FILE_BASIC_INFORMATION info;
377     IO_STATUS_BLOCK io;
378     NTSTATUS status;
379
380     memset( &info, 0, sizeof(info) );
381     if (ctime)
382     {
383         info.CreationTime.u.HighPart = ctime->dwHighDateTime;
384         info.CreationTime.u.LowPart  = ctime->dwLowDateTime;
385     }
386     if (atime)
387     {
388         info.LastAccessTime.u.HighPart = atime->dwHighDateTime;
389         info.LastAccessTime.u.LowPart  = atime->dwLowDateTime;
390     }
391     if (mtime)
392     {
393         info.LastWriteTime.u.HighPart = mtime->dwHighDateTime;
394         info.LastWriteTime.u.LowPart  = mtime->dwLowDateTime;
395     }
396
397     status = NtSetInformationFile( hFile, &io, &info, sizeof(info), FileBasicInformation );
398     if (status == STATUS_SUCCESS) return TRUE;
399     SetLastError( RtlNtStatusToDosError(status) );
400     return FALSE;
401 }
402
403
404 /**************************************************************************
405  *           LockFile   (KERNEL32.@)
406  */
407 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
408                       DWORD count_low, DWORD count_high )
409 {
410     NTSTATUS            status;
411     LARGE_INTEGER       count, offset;
412
413     TRACE( "%p %lx%08lx %lx%08lx\n", 
414            hFile, offset_high, offset_low, count_high, count_low );
415
416     count.u.LowPart = count_low;
417     count.u.HighPart = count_high;
418     offset.u.LowPart = offset_low;
419     offset.u.HighPart = offset_high;
420
421     status = NtLockFile( hFile, 0, NULL, NULL, 
422                          NULL, &offset, &count, NULL, TRUE, TRUE );
423     
424     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
425     return !status;
426 }
427
428
429 /**************************************************************************
430  * LockFileEx [KERNEL32.@]
431  *
432  * Locks a byte range within an open file for shared or exclusive access.
433  *
434  * RETURNS
435  *   success: TRUE
436  *   failure: FALSE
437  *
438  * NOTES
439  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
440  */
441 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
442                         DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
443 {
444     NTSTATUS status;
445     LARGE_INTEGER count, offset;
446
447     if (reserved)
448     {
449         SetLastError( ERROR_INVALID_PARAMETER );
450         return FALSE;
451     }
452
453     TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
454            hFile, overlapped->OffsetHigh, overlapped->Offset, 
455            count_high, count_low, flags );
456
457     count.u.LowPart = count_low;
458     count.u.HighPart = count_high;
459     offset.u.LowPart = overlapped->Offset;
460     offset.u.HighPart = overlapped->OffsetHigh;
461
462     status = NtLockFile( hFile, overlapped->hEvent, NULL, NULL, 
463                          NULL, &offset, &count, NULL, 
464                          flags & LOCKFILE_FAIL_IMMEDIATELY,
465                          flags & LOCKFILE_EXCLUSIVE_LOCK );
466     
467     if (status) SetLastError( RtlNtStatusToDosError(status) );
468     return !status;
469 }
470
471
472 /**************************************************************************
473  *           UnlockFile   (KERNEL32.@)
474  */
475 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
476                         DWORD count_low, DWORD count_high )
477 {
478     NTSTATUS    status;
479     LARGE_INTEGER count, offset;
480
481     count.u.LowPart = count_low;
482     count.u.HighPart = count_high;
483     offset.u.LowPart = offset_low;
484     offset.u.HighPart = offset_high;
485
486     status = NtUnlockFile( hFile, NULL, &offset, &count, NULL);
487     if (status) SetLastError( RtlNtStatusToDosError(status) );
488     return !status;
489 }
490
491
492 /**************************************************************************
493  *           UnlockFileEx   (KERNEL32.@)
494  */
495 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
496                           LPOVERLAPPED overlapped )
497 {
498     if (reserved)
499     {
500         SetLastError( ERROR_INVALID_PARAMETER );
501         return FALSE;
502     }
503     if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n");
504
505     return UnlockFile( hFile, overlapped->Offset, overlapped->OffsetHigh, count_low, count_high );
506 }
507
508
509 /***********************************************************************
510  *           Win32HandleToDosFileHandle   (KERNEL32.21)
511  *
512  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
513  * longer valid after this function (even on failure).
514  *
515  * Note: this is not exactly right, since on Win95 the Win32 handles
516  *       are on top of DOS handles and we do it the other way
517  *       around. Should be good enough though.
518  */
519 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
520 {
521     int i;
522
523     if (!handle || (handle == INVALID_HANDLE_VALUE))
524         return HFILE_ERROR;
525
526     FILE_InitProcessDosHandles();
527     for (i = 0; i < DOS_TABLE_SIZE; i++)
528         if (!dos_handles[i])
529         {
530             dos_handles[i] = handle;
531             TRACE("Got %d for h32 %p\n", i, handle );
532             return (HFILE)i;
533         }
534     CloseHandle( handle );
535     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
536     return HFILE_ERROR;
537 }
538
539
540 /***********************************************************************
541  *           DosFileHandleToWin32Handle   (KERNEL32.20)
542  *
543  * Return the Win32 handle for a DOS handle.
544  *
545  * Note: this is not exactly right, since on Win95 the Win32 handles
546  *       are on top of DOS handles and we do it the other way
547  *       around. Should be good enough though.
548  */
549 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
550 {
551     HFILE16 hfile = (HFILE16)handle;
552     if (hfile < 5) FILE_InitProcessDosHandles();
553     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
554     {
555         SetLastError( ERROR_INVALID_HANDLE );
556         return INVALID_HANDLE_VALUE;
557     }
558     return dos_handles[hfile];
559 }
560
561
562 /***********************************************************************
563  *           DisposeLZ32Handle   (KERNEL32.22)
564  *
565  * Note: this is not entirely correct, we should only close the
566  *       32-bit handle and not the 16-bit one, but we cannot do
567  *       this because of the way our DOS handles are implemented.
568  *       It shouldn't break anything though.
569  */
570 void WINAPI DisposeLZ32Handle( HANDLE handle )
571 {
572     int i;
573
574     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
575
576     for (i = 5; i < DOS_TABLE_SIZE; i++)
577         if (dos_handles[i] == handle)
578         {
579             dos_handles[i] = 0;
580             CloseHandle( handle );
581             break;
582         }
583 }
584
585 /**************************************************************************
586  *                      Operations on file names                          *
587  **************************************************************************/
588
589 /***********************************************************************
590  *           DeleteFileW   (KERNEL32.@)
591  */
592 BOOL WINAPI DeleteFileW( LPCWSTR path )
593 {
594     HANDLE hFile;
595
596     TRACE("%s\n", debugstr_w(path) );
597
598     hFile = CreateFileW( path, GENERIC_READ | GENERIC_WRITE,
599                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
600                          NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0 );
601     if (hFile == INVALID_HANDLE_VALUE) return FALSE;
602
603     CloseHandle(hFile);  /* last close will delete the file */
604     return TRUE;
605 }
606
607
608 /***********************************************************************
609  *           DeleteFileA   (KERNEL32.@)
610  */
611 BOOL WINAPI DeleteFileA( LPCSTR path )
612 {
613     UNICODE_STRING pathW;
614     BOOL ret = FALSE;
615
616     if (RtlCreateUnicodeStringFromAsciiz(&pathW, path))
617     {
618         ret = DeleteFileW(pathW.Buffer);
619         RtlFreeUnicodeString(&pathW);
620     }
621     else
622         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
623     return ret;
624 }
625
626
627 /**************************************************************************
628  *           ReplaceFileW   (KERNEL32.@)
629  *           ReplaceFile    (KERNEL32.@)
630  */
631 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
632                          LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
633                          LPVOID lpExclude, LPVOID lpReserved)
634 {
635     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
636                                           debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
637     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
638     return FALSE;
639 }
640
641
642 /**************************************************************************
643  *           ReplaceFileA (KERNEL32.@)
644  */
645 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
646                          LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
647                          LPVOID lpExclude, LPVOID lpReserved)
648 {
649     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
650                                           lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
651     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
652     return FALSE;
653 }
654
655
656 /*************************************************************************
657  *           FindFirstFileExW  (KERNEL32.@)
658  */
659 HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
660                                 LPVOID data, FINDEX_SEARCH_OPS search_op,
661                                 LPVOID filter, DWORD flags)
662 {
663     WCHAR *mask, *p;
664     FIND_FIRST_INFO *info = NULL;
665     UNICODE_STRING nt_name;
666     OBJECT_ATTRIBUTES attr;
667     IO_STATUS_BLOCK io;
668     NTSTATUS status;
669
670     if ((search_op != FindExSearchNameMatch) || (flags != 0))
671     {
672         FIXME("options not implemented 0x%08x 0x%08lx\n", search_op, flags );
673         return INVALID_HANDLE_VALUE;
674     }
675     if (level != FindExInfoStandard)
676     {
677         FIXME("info level %d not implemented\n", level );
678         return INVALID_HANDLE_VALUE;
679     }
680
681     if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, &mask, NULL ))
682     {
683         SetLastError( ERROR_PATH_NOT_FOUND );
684         return INVALID_HANDLE_VALUE;
685     }
686
687     if (!mask || !*mask)
688     {
689         SetLastError( ERROR_FILE_NOT_FOUND );
690         goto error;
691     }
692
693     if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info))))
694     {
695         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
696         goto error;
697     }
698
699     if (!RtlCreateUnicodeString( &info->mask, mask ))
700     {
701         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
702         goto error;
703     }
704
705     /* truncate dir name before mask */
706     *mask = 0;
707     nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
708
709     /* check if path is the root of the drive */
710     info->is_root = FALSE;
711     p = nt_name.Buffer + 4;  /* skip \??\ prefix */
712     if (p[0] && p[1] == ':')
713     {
714         p += 2;
715         while (*p == '\\') p++;
716         info->is_root = (*p == 0);
717     }
718
719     attr.Length = sizeof(attr);
720     attr.RootDirectory = 0;
721     attr.Attributes = OBJ_CASE_INSENSITIVE;
722     attr.ObjectName = &nt_name;
723     attr.SecurityDescriptor = NULL;
724     attr.SecurityQualityOfService = NULL;
725
726     status = NtOpenFile( &info->handle, GENERIC_READ, &attr, &io,
727                          FILE_SHARE_READ | FILE_SHARE_WRITE,
728                          FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
729
730     if (status != STATUS_SUCCESS)
731     {
732         RtlFreeUnicodeString( &info->mask );
733         SetLastError( RtlNtStatusToDosError(status) );
734         goto error;
735     }
736     RtlFreeUnicodeString( &nt_name );
737
738     RtlInitializeCriticalSection( &info->cs );
739     info->data_pos = 0;
740     info->data_len = 0;
741
742     if (!FindNextFileW( (HANDLE)info, data ))
743     {
744         TRACE( "%s not found\n", debugstr_w(filename) );
745         FindClose( (HANDLE)info );
746         SetLastError( ERROR_FILE_NOT_FOUND );
747         return INVALID_HANDLE_VALUE;
748     }
749     return (HANDLE)info;
750
751 error:
752     if (info) HeapFree( GetProcessHeap(), 0, info );
753     RtlFreeUnicodeString( &nt_name );
754     return INVALID_HANDLE_VALUE;
755 }
756
757
758 /*************************************************************************
759  *           FindNextFileW   (KERNEL32.@)
760  */
761 BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
762 {
763     FIND_FIRST_INFO *info;
764     FILE_BOTH_DIR_INFORMATION *dir_info;
765     BOOL ret = FALSE;
766
767     if (handle == INVALID_HANDLE_VALUE)
768     {
769         SetLastError( ERROR_INVALID_HANDLE );
770         return ret;
771     }
772     info = (FIND_FIRST_INFO *)handle;
773
774     RtlEnterCriticalSection( &info->cs );
775
776     for (;;)
777     {
778         if (info->data_pos >= info->data_len)  /* need to read some more data */
779         {
780             IO_STATUS_BLOCK io;
781
782             NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
783                                   FileBothDirectoryInformation, FALSE, &info->mask, FALSE );
784             if (io.u.Status)
785             {
786                 SetLastError( RtlNtStatusToDosError( io.u.Status ) );
787                 break;
788             }
789             info->data_len = io.Information;
790             info->data_pos = 0;
791         }
792
793         dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
794
795         if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset;
796         else info->data_pos = info->data_len;
797
798         /* don't return '.' and '..' in the root of the drive */
799         if (info->is_root)
800         {
801             if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue;
802             if (dir_info->FileNameLength == 2 * sizeof(WCHAR) &&
803                 dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue;
804         }
805
806         data->dwFileAttributes = dir_info->FileAttributes;
807         data->ftCreationTime   = *(FILETIME *)&dir_info->CreationTime;
808         data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
809         data->ftLastWriteTime  = *(FILETIME *)&dir_info->LastWriteTime;
810         data->nFileSizeHigh    = dir_info->EndOfFile.QuadPart >> 32;
811         data->nFileSizeLow     = (DWORD)dir_info->EndOfFile.QuadPart;
812         data->dwReserved0      = 0;
813         data->dwReserved1      = 0;
814
815         memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
816         data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
817         memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
818         data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0;
819
820         TRACE("returning %s (%s)\n",
821               debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) );
822
823         ret = TRUE;
824         break;
825     }
826
827     RtlLeaveCriticalSection( &info->cs );
828     return ret;
829 }
830
831
832 /*************************************************************************
833  *           FindClose   (KERNEL32.@)
834  */
835 BOOL WINAPI FindClose( HANDLE handle )
836 {
837     FIND_FIRST_INFO *info = (FIND_FIRST_INFO *)handle;
838
839     if (!handle || handle == INVALID_HANDLE_VALUE) goto error;
840
841     __TRY
842     {
843         RtlEnterCriticalSection( &info->cs );
844         if (info->handle) CloseHandle( info->handle );
845         info->handle = 0;
846         RtlFreeUnicodeString( &info->mask );
847         info->mask.Buffer = NULL;
848         info->data_pos = 0;
849         info->data_len = 0;
850     }
851     __EXCEPT(page_fault)
852     {
853         WARN("Illegal handle %p\n", handle);
854         SetLastError( ERROR_INVALID_HANDLE );
855         return FALSE;
856     }
857     __ENDTRY
858
859     RtlLeaveCriticalSection( &info->cs );
860     RtlDeleteCriticalSection( &info->cs );
861     HeapFree(GetProcessHeap(), 0, info);
862     return TRUE;
863
864  error:
865     SetLastError( ERROR_INVALID_HANDLE );
866     return FALSE;
867 }
868
869
870 /*************************************************************************
871  *           FindFirstFileA   (KERNEL32.@)
872  */
873 HANDLE WINAPI FindFirstFileA( LPCSTR lpFileName, WIN32_FIND_DATAA *lpFindData )
874 {
875     return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
876                             FindExSearchNameMatch, NULL, 0);
877 }
878
879 /*************************************************************************
880  *           FindFirstFileExA   (KERNEL32.@)
881  */
882 HANDLE WINAPI FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId,
883                                 LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp,
884                                 LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
885 {
886     HANDLE handle;
887     WIN32_FIND_DATAA *dataA;
888     WIN32_FIND_DATAW dataW;
889     UNICODE_STRING pathW;
890
891     if (!lpFileName)
892     {
893         SetLastError(ERROR_PATH_NOT_FOUND);
894         return INVALID_HANDLE_VALUE;
895     }
896
897     if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
898     {
899         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
900         return INVALID_HANDLE_VALUE;
901     }
902
903     handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
904     RtlFreeUnicodeString(&pathW);
905     if (handle == INVALID_HANDLE_VALUE) return handle;
906
907     dataA = (WIN32_FIND_DATAA *) lpFindFileData;
908     dataA->dwFileAttributes = dataW.dwFileAttributes;
909     dataA->ftCreationTime   = dataW.ftCreationTime;
910     dataA->ftLastAccessTime = dataW.ftLastAccessTime;
911     dataA->ftLastWriteTime  = dataW.ftLastWriteTime;
912     dataA->nFileSizeHigh    = dataW.nFileSizeHigh;
913     dataA->nFileSizeLow     = dataW.nFileSizeLow;
914     WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
915                          dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
916     WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
917                          dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
918     return handle;
919 }
920
921
922 /*************************************************************************
923  *           FindFirstFileW   (KERNEL32.@)
924  */
925 HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
926 {
927     return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
928                             FindExSearchNameMatch, NULL, 0);
929 }
930
931
932 /*************************************************************************
933  *           FindNextFileA   (KERNEL32.@)
934  */
935 BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
936 {
937     WIN32_FIND_DATAW dataW;
938
939     if (!FindNextFileW( handle, &dataW )) return FALSE;
940     data->dwFileAttributes = dataW.dwFileAttributes;
941     data->ftCreationTime   = dataW.ftCreationTime;
942     data->ftLastAccessTime = dataW.ftLastAccessTime;
943     data->ftLastWriteTime  = dataW.ftLastWriteTime;
944     data->nFileSizeHigh    = dataW.nFileSizeHigh;
945     data->nFileSizeLow     = dataW.nFileSizeLow;
946     WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
947                          data->cFileName, sizeof(data->cFileName), NULL, NULL );
948     WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
949                          data->cAlternateFileName,
950                          sizeof(data->cAlternateFileName), NULL, NULL );
951     return TRUE;
952 }
953
954
955 /**************************************************************************
956  *           GetFileAttributesW   (KERNEL32.@)
957  */
958 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
959 {
960     FILE_BASIC_INFORMATION info;
961     UNICODE_STRING nt_name;
962     OBJECT_ATTRIBUTES attr;
963     NTSTATUS status;
964
965     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
966     {
967         SetLastError( ERROR_PATH_NOT_FOUND );
968         return INVALID_FILE_ATTRIBUTES;
969     }
970
971     attr.Length = sizeof(attr);
972     attr.RootDirectory = 0;
973     attr.Attributes = OBJ_CASE_INSENSITIVE;
974     attr.ObjectName = &nt_name;
975     attr.SecurityDescriptor = NULL;
976     attr.SecurityQualityOfService = NULL;
977
978     status = NtQueryAttributesFile( &attr, &info );
979     RtlFreeUnicodeString( &nt_name );
980
981     if (status == STATUS_SUCCESS) return info.FileAttributes;
982
983     /* NtQueryAttributesFile fails on devices, but GetFileAttributesW succeeds */
984     if (RtlIsDosDeviceName_U( name )) return FILE_ATTRIBUTE_ARCHIVE;
985
986     SetLastError( RtlNtStatusToDosError(status) );
987     return INVALID_FILE_ATTRIBUTES;
988 }
989
990
991 /**************************************************************************
992  *           GetFileAttributesA   (KERNEL32.@)
993  */
994 DWORD WINAPI GetFileAttributesA( LPCSTR name )
995 {
996     UNICODE_STRING nameW;
997     DWORD ret = INVALID_FILE_ATTRIBUTES;
998
999     if (!name)
1000     {
1001         SetLastError( ERROR_INVALID_PARAMETER );
1002         return INVALID_FILE_ATTRIBUTES;
1003     }
1004
1005     if (RtlCreateUnicodeStringFromAsciiz(&nameW, name))
1006     {
1007         ret = GetFileAttributesW(nameW.Buffer);
1008         RtlFreeUnicodeString(&nameW);
1009     }
1010     else
1011         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1012     return ret;
1013 }
1014
1015
1016 /**************************************************************************
1017  *              SetFileAttributesW      (KERNEL32.@)
1018  */
1019 BOOL WINAPI SetFileAttributesW( LPCWSTR name, DWORD attributes )
1020 {
1021     UNICODE_STRING nt_name;
1022     OBJECT_ATTRIBUTES attr;
1023     IO_STATUS_BLOCK io;
1024     NTSTATUS status;
1025     HANDLE handle;
1026
1027     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1028     {
1029         SetLastError( ERROR_PATH_NOT_FOUND );
1030         return FALSE;
1031     }
1032
1033     attr.Length = sizeof(attr);
1034     attr.RootDirectory = 0;
1035     attr.Attributes = OBJ_CASE_INSENSITIVE;
1036     attr.ObjectName = &nt_name;
1037     attr.SecurityDescriptor = NULL;
1038     attr.SecurityQualityOfService = NULL;
1039
1040     status = NtOpenFile( &handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT );
1041     RtlFreeUnicodeString( &nt_name );
1042
1043     if (status == STATUS_SUCCESS)
1044     {
1045         FILE_BASIC_INFORMATION info;
1046
1047         memset( &info, 0, sizeof(info) );
1048         info.FileAttributes = attributes | FILE_ATTRIBUTE_NORMAL;  /* make sure it's not zero */
1049         status = NtSetInformationFile( handle, &io, &info, sizeof(info), FileBasicInformation );
1050         NtClose( handle );
1051     }
1052
1053     if (status == STATUS_SUCCESS) return TRUE;
1054     SetLastError( RtlNtStatusToDosError(status) );
1055     return FALSE;
1056 }
1057
1058
1059 /**************************************************************************
1060  *              SetFileAttributesA      (KERNEL32.@)
1061  */
1062 BOOL WINAPI SetFileAttributesA( LPCSTR name, DWORD attributes )
1063 {
1064     UNICODE_STRING filenameW;
1065     BOOL ret = FALSE;
1066
1067     if (!name)
1068     {
1069         SetLastError( ERROR_INVALID_PARAMETER );
1070         return FALSE;
1071     }
1072
1073     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, name))
1074     {
1075         ret = SetFileAttributesW(filenameW.Buffer, attributes);
1076         RtlFreeUnicodeString(&filenameW);
1077     }
1078     else
1079         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1080     return ret;
1081 }
1082
1083
1084 /**************************************************************************
1085  *           GetFileAttributesExW   (KERNEL32.@)
1086  */
1087 BOOL WINAPI GetFileAttributesExW( LPCWSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr )
1088 {
1089     FILE_NETWORK_OPEN_INFORMATION info;
1090     WIN32_FILE_ATTRIBUTE_DATA *data = ptr;
1091     UNICODE_STRING nt_name;
1092     OBJECT_ATTRIBUTES attr;
1093     NTSTATUS status;
1094
1095     if (level != GetFileExInfoStandard)
1096     {
1097         SetLastError( ERROR_INVALID_PARAMETER );
1098         return FALSE;
1099     }
1100
1101     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1102     {
1103         SetLastError( ERROR_PATH_NOT_FOUND );
1104         return FALSE;
1105     }
1106
1107     attr.Length = sizeof(attr);
1108     attr.RootDirectory = 0;
1109     attr.Attributes = OBJ_CASE_INSENSITIVE;
1110     attr.ObjectName = &nt_name;
1111     attr.SecurityDescriptor = NULL;
1112     attr.SecurityQualityOfService = NULL;
1113
1114     status = NtQueryFullAttributesFile( &attr, &info );
1115     RtlFreeUnicodeString( &nt_name );
1116
1117     if (status != STATUS_SUCCESS)
1118     {
1119         SetLastError( RtlNtStatusToDosError(status) );
1120         return FALSE;
1121     }
1122
1123     data->dwFileAttributes = info.FileAttributes;
1124     data->ftCreationTime.dwLowDateTime    = info.CreationTime.u.LowPart;
1125     data->ftCreationTime.dwHighDateTime   = info.CreationTime.u.HighPart;
1126     data->ftLastAccessTime.dwLowDateTime  = info.LastAccessTime.u.LowPart;
1127     data->ftLastAccessTime.dwHighDateTime = info.LastAccessTime.u.HighPart;
1128     data->ftLastWriteTime.dwLowDateTime   = info.LastWriteTime.u.LowPart;
1129     data->ftLastWriteTime.dwHighDateTime  = info.LastWriteTime.u.HighPart;
1130     data->nFileSizeLow                    = info.EndOfFile.u.LowPart;
1131     data->nFileSizeHigh                   = info.EndOfFile.u.HighPart;
1132     return TRUE;
1133 }
1134
1135
1136 /**************************************************************************
1137  *           GetFileAttributesExA   (KERNEL32.@)
1138  */
1139 BOOL WINAPI GetFileAttributesExA( LPCSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr )
1140 {
1141     UNICODE_STRING filenameW;
1142     BOOL ret = FALSE;
1143
1144     if (!name)
1145     {
1146         SetLastError(ERROR_INVALID_PARAMETER);
1147         return FALSE;
1148     }
1149
1150     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, name))
1151     {
1152         ret = GetFileAttributesExW(filenameW.Buffer, level, ptr);
1153         RtlFreeUnicodeString(&filenameW);
1154     }
1155     else
1156         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1157     return ret;
1158 }
1159
1160
1161 /******************************************************************************
1162  *           GetCompressedFileSizeW   (KERNEL32.@)
1163  *
1164  * RETURNS
1165  *    Success: Low-order doubleword of number of bytes
1166  *    Failure: INVALID_FILE_SIZE
1167  */
1168 DWORD WINAPI GetCompressedFileSizeW(
1169     LPCWSTR name,       /* [in]  Pointer to name of file */
1170     LPDWORD size_high ) /* [out] Receives high-order doubleword of size */
1171 {
1172     UNICODE_STRING nt_name;
1173     OBJECT_ATTRIBUTES attr;
1174     IO_STATUS_BLOCK io;
1175     NTSTATUS status;
1176     HANDLE handle;
1177     DWORD ret = INVALID_FILE_SIZE;
1178
1179     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1180     {
1181         SetLastError( ERROR_PATH_NOT_FOUND );
1182         return INVALID_FILE_SIZE;
1183     }
1184
1185     attr.Length = sizeof(attr);
1186     attr.RootDirectory = 0;
1187     attr.Attributes = OBJ_CASE_INSENSITIVE;
1188     attr.ObjectName = &nt_name;
1189     attr.SecurityDescriptor = NULL;
1190     attr.SecurityQualityOfService = NULL;
1191
1192     status = NtOpenFile( &handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT );
1193     RtlFreeUnicodeString( &nt_name );
1194
1195     if (status == STATUS_SUCCESS)
1196     {
1197         /* we don't support compressed files, simply return the file size */
1198         ret = GetFileSize( handle, size_high );
1199         NtClose( handle );
1200     }
1201     else SetLastError( RtlNtStatusToDosError(status) );
1202
1203     return ret;
1204 }
1205
1206
1207 /******************************************************************************
1208  *           GetCompressedFileSizeA   (KERNEL32.@)
1209  */
1210 DWORD WINAPI GetCompressedFileSizeA( LPCSTR name, LPDWORD size_high )
1211 {
1212     UNICODE_STRING filenameW;
1213     DWORD ret;
1214
1215     if (RtlCreateUnicodeStringFromAsciiz(&filenameW, name))
1216     {
1217         ret = GetCompressedFileSizeW(filenameW.Buffer, size_high);
1218         RtlFreeUnicodeString(&filenameW);
1219     }
1220     else
1221     {
1222         ret = INVALID_FILE_SIZE;
1223         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1224     }
1225     return ret;
1226 }
1227
1228
1229 /***********************************************************************
1230  *           OpenFile   (KERNEL32.@)
1231  */
1232 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
1233 {
1234     HANDLE handle;
1235     FILETIME filetime;
1236     WORD filedatetime[2];
1237
1238     if (!ofs) return HFILE_ERROR;
1239
1240     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
1241           ((mode & 0x3 )==OF_READ)?"OF_READ":
1242           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
1243           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
1244           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
1245           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
1246           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
1247           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
1248           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
1249           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
1250           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
1251           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
1252           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
1253           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
1254           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
1255           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
1256           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
1257           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
1258         );
1259
1260
1261     ofs->cBytes = sizeof(OFSTRUCT);
1262     ofs->nErrCode = 0;
1263     if (mode & OF_REOPEN) name = ofs->szPathName;
1264
1265     if (!name) return HFILE_ERROR;
1266
1267     TRACE("%s %04x\n", name, mode );
1268
1269     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1270        Are there any cases where getting the path here is wrong?
1271        Uwe Bonnes 1997 Apr 2 */
1272     if (!GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL )) goto error;
1273
1274     /* OF_PARSE simply fills the structure */
1275
1276     if (mode & OF_PARSE)
1277     {
1278         ofs->fFixedDisk = (GetDriveTypeA( ofs->szPathName ) != DRIVE_REMOVABLE);
1279         TRACE("(%s): OF_PARSE, res = '%s'\n", name, ofs->szPathName );
1280         return 0;
1281     }
1282
1283     /* OF_CREATE is completely different from all other options, so
1284        handle it first */
1285
1286     if (mode & OF_CREATE)
1287     {
1288         DWORD access, sharing;
1289         FILE_ConvertOFMode( mode, &access, &sharing );
1290         if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
1291                                    sharing, NULL, CREATE_ALWAYS,
1292                                    FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1293             goto error;
1294     }
1295     else
1296     {
1297         /* Now look for the file */
1298
1299         if (!SearchPathA( NULL, name, NULL, sizeof(ofs->szPathName), ofs->szPathName, NULL ))
1300             goto error;
1301
1302         TRACE("found %s\n", debugstr_a(ofs->szPathName) );
1303
1304         if (mode & OF_DELETE)
1305         {
1306             if (!DeleteFileA( ofs->szPathName )) goto error;
1307             TRACE("(%s): OF_DELETE return = OK\n", name);
1308             return TRUE;
1309         }
1310
1311         handle = (HANDLE)_lopen( ofs->szPathName, mode );
1312         if (handle == INVALID_HANDLE_VALUE) goto error;
1313
1314         GetFileTime( handle, NULL, NULL, &filetime );
1315         FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
1316         if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
1317         {
1318             if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
1319             {
1320                 CloseHandle( handle );
1321                 WARN("(%s): OF_VERIFY failed\n", name );
1322                 /* FIXME: what error here? */
1323                 SetLastError( ERROR_FILE_NOT_FOUND );
1324                 goto error;
1325             }
1326         }
1327         ofs->Reserved1 = filedatetime[0];
1328         ofs->Reserved2 = filedatetime[1];
1329     }
1330     TRACE("(%s): OK, return = %p\n", name, handle );
1331     if (mode & OF_EXIST)  /* Return TRUE instead of a handle */
1332     {
1333         CloseHandle( handle );
1334         return TRUE;
1335     }
1336     else return (HFILE)handle;
1337
1338 error:  /* We get here if there was an error opening the file */
1339     ofs->nErrCode = GetLastError();
1340     WARN("(%s): return = HFILE_ERROR error= %d\n", name,ofs->nErrCode );
1341     return HFILE_ERROR;
1342 }