kernel32: Reimplement GetPrivateProfileString16 on top of 32-bit functions and move...
[wine] / dlls / kernel32 / file.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 John Burton
5  * Copyright 1996, 2004 Alexandre Julliard
6  * Copyright 2008 Jeff Zaroyko
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "winerror.h"
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winternl.h"
41 #include "winioctl.h"
42 #include "wincon.h"
43 #include "wine/winbase16.h"
44 #include "kernel_private.h"
45
46 #include "wine/exception.h"
47 #include "wine/unicode.h"
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(file);
51
52 HANDLE dos_handles[DOS_TABLE_SIZE];
53
54 /* info structure for FindFirstFile handle */
55 typedef struct
56 {
57     DWORD             magic;       /* magic number */
58     HANDLE            handle;      /* handle to directory */
59     CRITICAL_SECTION  cs;          /* crit section protecting this structure */
60     FINDEX_SEARCH_OPS search_op;   /* Flags passed to FindFirst.  */
61     UNICODE_STRING    mask;        /* file mask */
62     UNICODE_STRING    path;        /* NT path used to open the directory */
63     BOOL              is_root;     /* is directory the root of the drive? */
64     UINT              data_pos;    /* current position in dir data */
65     UINT              data_len;    /* length of dir data */
66     BYTE              data[8192];  /* directory data */
67 } FIND_FIRST_INFO;
68
69 #define FIND_FIRST_MAGIC  0xc0ffee11
70
71 static BOOL oem_file_apis;
72
73 static const WCHAR wildcardsW[] = { '*','?',0 };
74
75 /***********************************************************************
76  *              create_file_OF
77  *
78  * Wrapper for CreateFile that takes OF_* mode flags.
79  */
80 static HANDLE create_file_OF( LPCSTR path, INT mode )
81 {
82     DWORD access, sharing, creation;
83
84     if (mode & OF_CREATE)
85     {
86         creation = CREATE_ALWAYS;
87         access = GENERIC_READ | GENERIC_WRITE;
88     }
89     else
90     {
91         creation = OPEN_EXISTING;
92         switch(mode & 0x03)
93         {
94         case OF_READ:      access = GENERIC_READ; break;
95         case OF_WRITE:     access = GENERIC_WRITE; break;
96         case OF_READWRITE: access = GENERIC_READ | GENERIC_WRITE; break;
97         default:           access = 0; break;
98         }
99     }
100
101     switch(mode & 0x70)
102     {
103     case OF_SHARE_EXCLUSIVE:  sharing = 0; break;
104     case OF_SHARE_DENY_WRITE: sharing = FILE_SHARE_READ; break;
105     case OF_SHARE_DENY_READ:  sharing = FILE_SHARE_WRITE; break;
106     case OF_SHARE_DENY_NONE:
107     case OF_SHARE_COMPAT:
108     default:                  sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
109     }
110     return CreateFileA( path, access, sharing, NULL, creation, FILE_ATTRIBUTE_NORMAL, 0 );
111 }
112
113
114 /***********************************************************************
115  *              check_dir_symlink
116  *
117  * Check if a dir symlink should be returned by FindNextFile.
118  */
119 static BOOL check_dir_symlink( FIND_FIRST_INFO *info, const FILE_BOTH_DIR_INFORMATION *file_info )
120 {
121     UNICODE_STRING str;
122     ANSI_STRING unix_name;
123     struct stat st, parent_st;
124     BOOL ret = TRUE;
125     DWORD len;
126
127     str.MaximumLength = info->path.Length + sizeof(WCHAR) + file_info->FileNameLength;
128     if (!(str.Buffer = HeapAlloc( GetProcessHeap(), 0, str.MaximumLength ))) return TRUE;
129     memcpy( str.Buffer, info->path.Buffer, info->path.Length );
130     len = info->path.Length / sizeof(WCHAR);
131     if (!len || str.Buffer[len-1] != '\\') str.Buffer[len++] = '\\';
132     memcpy( str.Buffer + len, file_info->FileName, file_info->FileNameLength );
133     str.Length = len * sizeof(WCHAR) + file_info->FileNameLength;
134
135     unix_name.Buffer = NULL;
136     if (!wine_nt_to_unix_file_name( &str, &unix_name, OPEN_EXISTING, FALSE ) &&
137         !stat( unix_name.Buffer, &st ))
138     {
139         char *p = unix_name.Buffer + unix_name.Length - 1;
140
141         /* skip trailing slashes */
142         while (p > unix_name.Buffer && *p == '/') p--;
143
144         while (ret && p > unix_name.Buffer)
145         {
146             while (p > unix_name.Buffer && *p != '/') p--;
147             while (p > unix_name.Buffer && *p == '/') p--;
148             p[1] = 0;
149             if (!stat( unix_name.Buffer, &parent_st ) &&
150                 parent_st.st_dev == st.st_dev &&
151                 parent_st.st_ino == st.st_ino)
152             {
153                 WARN( "suppressing dir symlink %s pointing to parent %s\n",
154                       debugstr_wn( str.Buffer, str.Length/sizeof(WCHAR) ),
155                       debugstr_a( unix_name.Buffer ));
156                 ret = FALSE;
157             }
158         }
159     }
160     RtlFreeAnsiString( &unix_name );
161     RtlFreeUnicodeString( &str );
162     return ret;
163 }
164
165
166 /***********************************************************************
167  *           FILE_SetDosError
168  *
169  * Set the DOS error code from errno.
170  */
171 void FILE_SetDosError(void)
172 {
173     int save_errno = errno; /* errno gets overwritten by printf */
174
175     TRACE("errno = %d %s\n", errno, strerror(errno));
176     switch (save_errno)
177     {
178     case EAGAIN:
179         SetLastError( ERROR_SHARING_VIOLATION );
180         break;
181     case EBADF:
182         SetLastError( ERROR_INVALID_HANDLE );
183         break;
184     case ENOSPC:
185         SetLastError( ERROR_HANDLE_DISK_FULL );
186         break;
187     case EACCES:
188     case EPERM:
189     case EROFS:
190         SetLastError( ERROR_ACCESS_DENIED );
191         break;
192     case EBUSY:
193         SetLastError( ERROR_LOCK_VIOLATION );
194         break;
195     case ENOENT:
196         SetLastError( ERROR_FILE_NOT_FOUND );
197         break;
198     case EISDIR:
199         SetLastError( ERROR_CANNOT_MAKE );
200         break;
201     case ENFILE:
202     case EMFILE:
203         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
204         break;
205     case EEXIST:
206         SetLastError( ERROR_FILE_EXISTS );
207         break;
208     case EINVAL:
209     case ESPIPE:
210         SetLastError( ERROR_SEEK );
211         break;
212     case ENOTEMPTY:
213         SetLastError( ERROR_DIR_NOT_EMPTY );
214         break;
215     case ENOEXEC:
216         SetLastError( ERROR_BAD_FORMAT );
217         break;
218     case ENOTDIR:
219         SetLastError( ERROR_PATH_NOT_FOUND );
220         break;
221     case EXDEV:
222         SetLastError( ERROR_NOT_SAME_DEVICE );
223         break;
224     default:
225         WARN("unknown file error: %s\n", strerror(save_errno) );
226         SetLastError( ERROR_GEN_FAILURE );
227         break;
228     }
229     errno = save_errno;
230 }
231
232
233 /***********************************************************************
234  *           FILE_name_AtoW
235  *
236  * Convert a file name to Unicode, taking into account the OEM/Ansi API mode.
237  *
238  * If alloc is FALSE uses the TEB static buffer, so it can only be used when
239  * there is no possibility for the function to do that twice, taking into
240  * account any called function.
241  */
242 WCHAR *FILE_name_AtoW( LPCSTR name, BOOL alloc )
243 {
244     ANSI_STRING str;
245     UNICODE_STRING strW, *pstrW;
246     NTSTATUS status;
247
248     RtlInitAnsiString( &str, name );
249     pstrW = alloc ? &strW : &NtCurrentTeb()->StaticUnicodeString;
250     if (oem_file_apis)
251         status = RtlOemStringToUnicodeString( pstrW, &str, alloc );
252     else
253         status = RtlAnsiStringToUnicodeString( pstrW, &str, alloc );
254     if (status == STATUS_SUCCESS) return pstrW->Buffer;
255
256     if (status == STATUS_BUFFER_OVERFLOW)
257         SetLastError( ERROR_FILENAME_EXCED_RANGE );
258     else
259         SetLastError( RtlNtStatusToDosError(status) );
260     return NULL;
261 }
262
263
264 /***********************************************************************
265  *           FILE_name_WtoA
266  *
267  * Convert a file name back to OEM/Ansi. Returns number of bytes copied.
268  */
269 DWORD FILE_name_WtoA( LPCWSTR src, INT srclen, LPSTR dest, INT destlen )
270 {
271     DWORD ret;
272
273     if (srclen < 0) srclen = strlenW( src ) + 1;
274     if (oem_file_apis)
275         RtlUnicodeToOemN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) );
276     else
277         RtlUnicodeToMultiByteN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) );
278     return ret;
279 }
280
281
282 /**************************************************************************
283  *              SetFileApisToOEM   (KERNEL32.@)
284  */
285 VOID WINAPI SetFileApisToOEM(void)
286 {
287     oem_file_apis = TRUE;
288 }
289
290
291 /**************************************************************************
292  *              SetFileApisToANSI   (KERNEL32.@)
293  */
294 VOID WINAPI SetFileApisToANSI(void)
295 {
296     oem_file_apis = FALSE;
297 }
298
299
300 /******************************************************************************
301  *              AreFileApisANSI   (KERNEL32.@)
302  *
303  *  Determines if file functions are using ANSI
304  *
305  * RETURNS
306  *    TRUE:  Set of file functions is using ANSI code page
307  *    FALSE: Set of file functions is using OEM code page
308  */
309 BOOL WINAPI AreFileApisANSI(void)
310 {
311     return !oem_file_apis;
312 }
313
314
315 /**************************************************************************
316  *                      Operations on file handles                        *
317  **************************************************************************/
318
319 /***********************************************************************
320  *           FILE_InitProcessDosHandles
321  *
322  * Allocates the default DOS handles for a process. Called either by
323  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
324  */
325 static void FILE_InitProcessDosHandles( void )
326 {
327     static BOOL init_done /* = FALSE */;
328     HANDLE cp = GetCurrentProcess();
329
330     if (init_done) return;
331     init_done = TRUE;
332     DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
333                     0, TRUE, DUPLICATE_SAME_ACCESS);
334     DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
335                     0, TRUE, DUPLICATE_SAME_ACCESS);
336     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
337                     0, TRUE, DUPLICATE_SAME_ACCESS);
338     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
339                     0, TRUE, DUPLICATE_SAME_ACCESS);
340     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
341                     0, TRUE, DUPLICATE_SAME_ACCESS);
342 }
343
344
345 /******************************************************************
346  *              FILE_ReadWriteApc (internal)
347  */
348 static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG reserved)
349 {
350     LPOVERLAPPED_COMPLETION_ROUTINE  cr = apc_user;
351
352     cr(RtlNtStatusToDosError(io_status->u.Status), io_status->Information, (LPOVERLAPPED)io_status);
353 }
354
355
356 /***********************************************************************
357  *              ReadFileEx                (KERNEL32.@)
358  */
359 BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
360                        LPOVERLAPPED overlapped,
361                        LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
362 {
363     LARGE_INTEGER       offset;
364     NTSTATUS            status;
365     PIO_STATUS_BLOCK    io_status;
366
367     TRACE("(hFile=%p, buffer=%p, bytes=%u, ovl=%p, ovl_fn=%p)\n", hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
368
369     if (!overlapped)
370     {
371         SetLastError(ERROR_INVALID_PARAMETER);
372         return FALSE;
373     }
374
375     offset.u.LowPart = overlapped->u.s.Offset;
376     offset.u.HighPart = overlapped->u.s.OffsetHigh;
377     io_status = (PIO_STATUS_BLOCK)overlapped;
378     io_status->u.Status = STATUS_PENDING;
379     io_status->Information = 0;
380
381     status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
382                         io_status, buffer, bytesToRead, &offset, NULL);
383
384     if (status)
385     {
386         SetLastError( RtlNtStatusToDosError(status) );
387         return FALSE;
388     }
389     return TRUE;
390 }
391
392
393 /***********************************************************************
394  *              ReadFileScatter                (KERNEL32.@)
395  */
396 BOOL WINAPI ReadFileScatter( HANDLE file, FILE_SEGMENT_ELEMENT *segments, DWORD count,
397                              LPDWORD reserved, LPOVERLAPPED overlapped )
398 {
399     PIO_STATUS_BLOCK io_status;
400     LARGE_INTEGER offset;
401     NTSTATUS status;
402
403     TRACE( "(%p %p %u %p)\n", file, segments, count, overlapped );
404
405     offset.u.LowPart = overlapped->u.s.Offset;
406     offset.u.HighPart = overlapped->u.s.OffsetHigh;
407     io_status = (PIO_STATUS_BLOCK)overlapped;
408     io_status->u.Status = STATUS_PENDING;
409     io_status->Information = 0;
410
411     status = NtReadFileScatter( file, NULL, NULL, NULL, io_status, segments, count, &offset, NULL );
412     if (status) SetLastError( RtlNtStatusToDosError(status) );
413     return !status;
414 }
415
416
417 /***********************************************************************
418  *              ReadFile                (KERNEL32.@)
419  */
420 BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
421                       LPDWORD bytesRead, LPOVERLAPPED overlapped )
422 {
423     LARGE_INTEGER       offset;
424     PLARGE_INTEGER      poffset = NULL;
425     IO_STATUS_BLOCK     iosb;
426     PIO_STATUS_BLOCK    io_status = &iosb;
427     HANDLE              hEvent = 0;
428     NTSTATUS            status;
429     LPVOID              cvalue = NULL;
430
431     TRACE("%p %p %d %p %p\n", hFile, buffer, bytesToRead,
432           bytesRead, overlapped );
433
434     if (bytesRead) *bytesRead = 0;  /* Do this before anything else */
435     if (!bytesToRead) return TRUE;
436
437     if (is_console_handle(hFile))
438         return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
439
440     if (overlapped != NULL)
441     {
442         offset.u.LowPart = overlapped->u.s.Offset;
443         offset.u.HighPart = overlapped->u.s.OffsetHigh;
444         poffset = &offset;
445         hEvent = overlapped->hEvent;
446         io_status = (PIO_STATUS_BLOCK)overlapped;
447         if (((ULONG_PTR)hEvent & 1) == 0) cvalue = overlapped;
448     }
449     io_status->u.Status = STATUS_PENDING;
450     io_status->Information = 0;
451
452     status = NtReadFile(hFile, hEvent, NULL, cvalue, io_status, buffer, bytesToRead, poffset, NULL);
453
454     if (status == STATUS_PENDING && !overlapped)
455     {
456         WaitForSingleObject( hFile, INFINITE );
457         status = io_status->u.Status;
458     }
459
460     if (status != STATUS_PENDING && bytesRead)
461         *bytesRead = io_status->Information;
462
463     if (status && status != STATUS_END_OF_FILE && status != STATUS_TIMEOUT)
464     {
465         SetLastError( RtlNtStatusToDosError(status) );
466         return FALSE;
467     }
468     return TRUE;
469 }
470
471
472 /***********************************************************************
473  *              WriteFileEx                (KERNEL32.@)
474  */
475 BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
476                         LPOVERLAPPED overlapped,
477                         LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
478 {
479     LARGE_INTEGER       offset;
480     NTSTATUS            status;
481     PIO_STATUS_BLOCK    io_status;
482
483     TRACE("%p %p %d %p %p\n", hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
484
485     if (overlapped == NULL)
486     {
487         SetLastError(ERROR_INVALID_PARAMETER);
488         return FALSE;
489     }
490     offset.u.LowPart = overlapped->u.s.Offset;
491     offset.u.HighPart = overlapped->u.s.OffsetHigh;
492
493     io_status = (PIO_STATUS_BLOCK)overlapped;
494     io_status->u.Status = STATUS_PENDING;
495     io_status->Information = 0;
496
497     status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine,
498                          io_status, buffer, bytesToWrite, &offset, NULL);
499
500     if (status) SetLastError( RtlNtStatusToDosError(status) );
501     return !status;
502 }
503
504
505 /***********************************************************************
506  *              WriteFileGather                (KERNEL32.@)
507  */
508 BOOL WINAPI WriteFileGather( HANDLE file, FILE_SEGMENT_ELEMENT *segments, DWORD count,
509                              LPDWORD reserved, LPOVERLAPPED overlapped )
510 {
511     PIO_STATUS_BLOCK io_status;
512     LARGE_INTEGER offset;
513     NTSTATUS status;
514
515     TRACE( "%p %p %u %p\n", file, segments, count, overlapped );
516
517     offset.u.LowPart = overlapped->u.s.Offset;
518     offset.u.HighPart = overlapped->u.s.OffsetHigh;
519     io_status = (PIO_STATUS_BLOCK)overlapped;
520     io_status->u.Status = STATUS_PENDING;
521     io_status->Information = 0;
522
523     status = NtWriteFileGather( file, NULL, NULL, NULL, io_status, segments, count, &offset, NULL );
524     if (status) SetLastError( RtlNtStatusToDosError(status) );
525     return !status;
526 }
527
528
529 /***********************************************************************
530  *             WriteFile               (KERNEL32.@)
531  */
532 BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
533                        LPDWORD bytesWritten, LPOVERLAPPED overlapped )
534 {
535     HANDLE hEvent = NULL;
536     LARGE_INTEGER offset;
537     PLARGE_INTEGER poffset = NULL;
538     NTSTATUS status;
539     IO_STATUS_BLOCK iosb;
540     PIO_STATUS_BLOCK piosb = &iosb;
541     LPVOID cvalue = NULL;
542
543     TRACE("%p %p %d %p %p\n", hFile, buffer, bytesToWrite, bytesWritten, overlapped );
544
545     if (is_console_handle(hFile))
546         return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
547
548     if (overlapped)
549     {
550         offset.u.LowPart = overlapped->u.s.Offset;
551         offset.u.HighPart = overlapped->u.s.OffsetHigh;
552         poffset = &offset;
553         hEvent = overlapped->hEvent;
554         piosb = (PIO_STATUS_BLOCK)overlapped;
555         if (((ULONG_PTR)hEvent & 1) == 0) cvalue = overlapped;
556     }
557     piosb->u.Status = STATUS_PENDING;
558     piosb->Information = 0;
559
560     status = NtWriteFile(hFile, hEvent, NULL, cvalue, piosb,
561                          buffer, bytesToWrite, poffset, NULL);
562
563     if (status == STATUS_PENDING && !overlapped)
564     {
565         WaitForSingleObject( hFile, INFINITE );
566         status = piosb->u.Status;
567     }
568
569     if (status != STATUS_PENDING && bytesWritten)
570         *bytesWritten = piosb->Information;
571
572     if (status && status != STATUS_TIMEOUT)
573     {
574         SetLastError( RtlNtStatusToDosError(status) );
575         return FALSE;
576     }
577     return TRUE;
578 }
579
580
581 /***********************************************************************
582  *              GetOverlappedResult     (KERNEL32.@)
583  *
584  * Check the result of an Asynchronous data transfer from a file.
585  *
586  * Parameters
587  *   HANDLE hFile                 [in] handle of file to check on
588  *   LPOVERLAPPED lpOverlapped    [in/out] pointer to overlapped
589  *   LPDWORD lpTransferred        [in/out] number of bytes transferred
590  *   BOOL bWait                   [in] wait for the transfer to complete ?
591  *
592  * RETURNS
593  *   TRUE on success
594  *   FALSE on failure
595  *
596  *  If successful (and relevant) lpTransferred will hold the number of
597  *   bytes transferred during the async operation.
598  */
599 BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
600                                 LPDWORD lpTransferred, BOOL bWait)
601 {
602     NTSTATUS status;
603
604     TRACE( "(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait );
605
606     status = lpOverlapped->Internal;
607     if (status == STATUS_PENDING)
608     {
609         if (!bWait)
610         {
611             SetLastError( ERROR_IO_INCOMPLETE );
612             return FALSE;
613         }
614
615         if (WaitForSingleObject( lpOverlapped->hEvent ? lpOverlapped->hEvent : hFile,
616                                  INFINITE ) == WAIT_FAILED)
617             return FALSE;
618         status = lpOverlapped->Internal;
619     }
620
621     *lpTransferred = lpOverlapped->InternalHigh;
622
623     if (status) SetLastError( RtlNtStatusToDosError(status) );
624     return !status;
625 }
626
627 /***********************************************************************
628  *             CancelIoEx                 (KERNEL32.@)
629  *
630  * Cancels pending I/O operations on a file given the overlapped used.
631  *
632  * PARAMS
633  *  handle        [I] File handle.
634  *  lpOverlapped  [I,OPT] pointer to overlapped (if null, cancel all)
635  *
636  * RETURNS
637  *  Success: TRUE.
638  *  Failure: FALSE, check GetLastError().
639  */
640 BOOL WINAPI CancelIoEx(HANDLE handle, LPOVERLAPPED lpOverlapped)
641 {
642     IO_STATUS_BLOCK    io_status;
643
644     NtCancelIoFileEx(handle, (PIO_STATUS_BLOCK) lpOverlapped, &io_status);
645     if (io_status.u.Status)
646     {
647         SetLastError( RtlNtStatusToDosError( io_status.u.Status ) );
648         return FALSE;
649     }
650     return TRUE;
651 }
652
653 /***********************************************************************
654  *             CancelIo                   (KERNEL32.@)
655  *
656  * Cancels pending I/O operations initiated by the current thread on a file.
657  *
658  * PARAMS
659  *  handle [I] File handle.
660  *
661  * RETURNS
662  *  Success: TRUE.
663  *  Failure: FALSE, check GetLastError().
664  */
665 BOOL WINAPI CancelIo(HANDLE handle)
666 {
667     IO_STATUS_BLOCK    io_status;
668
669     NtCancelIoFile(handle, &io_status);
670     if (io_status.u.Status)
671     {
672         SetLastError( RtlNtStatusToDosError( io_status.u.Status ) );
673         return FALSE;
674     }
675     return TRUE;
676 }
677
678 /***********************************************************************
679  *           _hread   (KERNEL32.@)
680  */
681 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
682 {
683     return _lread( hFile, buffer, count );
684 }
685
686
687 /***********************************************************************
688  *           _hwrite   (KERNEL32.@)
689  *
690  *      experimentation yields that _lwrite:
691  *              o truncates the file at the current position with
692  *                a 0 len write
693  *              o returns 0 on a 0 length write
694  *              o works with console handles
695  *
696  */
697 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
698 {
699     DWORD result;
700
701     TRACE("%d %p %d\n", handle, buffer, count );
702
703     if (!count)
704     {
705         /* Expand or truncate at current position */
706         if (!SetEndOfFile( LongToHandle(handle) )) return HFILE_ERROR;
707         return 0;
708     }
709     if (!WriteFile( LongToHandle(handle), buffer, count, &result, NULL ))
710         return HFILE_ERROR;
711     return result;
712 }
713
714
715 /***********************************************************************
716  *           _lclose   (KERNEL32.@)
717  */
718 HFILE WINAPI _lclose( HFILE hFile )
719 {
720     TRACE("handle %d\n", hFile );
721     return CloseHandle( LongToHandle(hFile) ) ? 0 : HFILE_ERROR;
722 }
723
724
725 /***********************************************************************
726  *           _lcreat   (KERNEL32.@)
727  */
728 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
729 {
730     HANDLE hfile;
731
732     /* Mask off all flags not explicitly allowed by the doc */
733     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
734     TRACE("%s %02x\n", path, attr );
735     hfile = CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
736                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
737                                CREATE_ALWAYS, attr, 0 );
738     return HandleToLong(hfile);
739 }
740
741
742 /***********************************************************************
743  *           _lopen   (KERNEL32.@)
744  */
745 HFILE WINAPI _lopen( LPCSTR path, INT mode )
746 {
747     HANDLE hfile;
748
749     TRACE("(%s,%04x)\n", debugstr_a(path), mode );
750     hfile = create_file_OF( path, mode & ~OF_CREATE );
751     return HandleToLong(hfile);
752 }
753
754 /***********************************************************************
755  *           _lread   (KERNEL32.@)
756  */
757 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
758 {
759     DWORD result;
760     if (!ReadFile( LongToHandle(handle), buffer, count, &result, NULL ))
761         return HFILE_ERROR;
762     return result;
763 }
764
765
766 /***********************************************************************
767  *           _llseek   (KERNEL32.@)
768  */
769 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
770 {
771     return SetFilePointer( LongToHandle(hFile), lOffset, NULL, nOrigin );
772 }
773
774
775 /***********************************************************************
776  *           _lwrite   (KERNEL32.@)
777  */
778 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
779 {
780     return (UINT)_hwrite( hFile, buffer, (LONG)count );
781 }
782
783
784 /***********************************************************************
785  *           FlushFileBuffers   (KERNEL32.@)
786  */
787 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
788 {
789     NTSTATUS            nts;
790     IO_STATUS_BLOCK     ioblk;
791
792     if (is_console_handle( hFile ))
793     {
794         /* this will fail (as expected) for an output handle */
795         return FlushConsoleInputBuffer( hFile );
796     }
797     nts = NtFlushBuffersFile( hFile, &ioblk );
798     if (nts != STATUS_SUCCESS)
799     {
800         SetLastError( RtlNtStatusToDosError( nts ) );
801         return FALSE;
802     }
803
804     return TRUE;
805 }
806
807
808 /***********************************************************************
809  *           GetFileType   (KERNEL32.@)
810  */
811 DWORD WINAPI GetFileType( HANDLE hFile )
812 {
813     FILE_FS_DEVICE_INFORMATION info;
814     IO_STATUS_BLOCK io;
815     NTSTATUS status;
816
817     if (is_console_handle( hFile )) return FILE_TYPE_CHAR;
818
819     status = NtQueryVolumeInformationFile( hFile, &io, &info, sizeof(info), FileFsDeviceInformation );
820     if (status != STATUS_SUCCESS)
821     {
822         SetLastError( RtlNtStatusToDosError(status) );
823         return FILE_TYPE_UNKNOWN;
824     }
825
826     switch(info.DeviceType)
827     {
828     case FILE_DEVICE_NULL:
829     case FILE_DEVICE_SERIAL_PORT:
830     case FILE_DEVICE_PARALLEL_PORT:
831     case FILE_DEVICE_TAPE:
832     case FILE_DEVICE_UNKNOWN:
833         return FILE_TYPE_CHAR;
834     case FILE_DEVICE_NAMED_PIPE:
835         return FILE_TYPE_PIPE;
836     default:
837         return FILE_TYPE_DISK;
838     }
839 }
840
841
842 /***********************************************************************
843  *             GetFileInformationByHandle   (KERNEL32.@)
844  */
845 BOOL WINAPI GetFileInformationByHandle( HANDLE hFile, BY_HANDLE_FILE_INFORMATION *info )
846 {
847     FILE_ALL_INFORMATION all_info;
848     IO_STATUS_BLOCK io;
849     NTSTATUS status;
850
851     status = NtQueryInformationFile( hFile, &io, &all_info, sizeof(all_info), FileAllInformation );
852     if (status == STATUS_SUCCESS)
853     {
854         info->dwFileAttributes                = all_info.BasicInformation.FileAttributes;
855         info->ftCreationTime.dwHighDateTime   = all_info.BasicInformation.CreationTime.u.HighPart;
856         info->ftCreationTime.dwLowDateTime    = all_info.BasicInformation.CreationTime.u.LowPart;
857         info->ftLastAccessTime.dwHighDateTime = all_info.BasicInformation.LastAccessTime.u.HighPart;
858         info->ftLastAccessTime.dwLowDateTime  = all_info.BasicInformation.LastAccessTime.u.LowPart;
859         info->ftLastWriteTime.dwHighDateTime  = all_info.BasicInformation.LastWriteTime.u.HighPart;
860         info->ftLastWriteTime.dwLowDateTime   = all_info.BasicInformation.LastWriteTime.u.LowPart;
861         info->dwVolumeSerialNumber            = 0;  /* FIXME */
862         info->nFileSizeHigh                   = all_info.StandardInformation.EndOfFile.u.HighPart;
863         info->nFileSizeLow                    = all_info.StandardInformation.EndOfFile.u.LowPart;
864         info->nNumberOfLinks                  = all_info.StandardInformation.NumberOfLinks;
865         info->nFileIndexHigh                  = all_info.InternalInformation.IndexNumber.u.HighPart;
866         info->nFileIndexLow                   = all_info.InternalInformation.IndexNumber.u.LowPart;
867         return TRUE;
868     }
869     SetLastError( RtlNtStatusToDosError(status) );
870     return FALSE;
871 }
872
873
874 /***********************************************************************
875  *           GetFileSize   (KERNEL32.@)
876  *
877  * Retrieve the size of a file.
878  *
879  * PARAMS
880  *  hFile        [I] File to retrieve size of.
881  *  filesizehigh [O] On return, the high bits of the file size.
882  *
883  * RETURNS
884  *  Success: The low bits of the file size.
885  *  Failure: INVALID_FILE_SIZE. As this is could also be a success value,
886  *           check GetLastError() for values other than ERROR_SUCCESS.
887  */
888 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
889 {
890     LARGE_INTEGER size;
891     if (!GetFileSizeEx( hFile, &size )) return INVALID_FILE_SIZE;
892     if (filesizehigh) *filesizehigh = size.u.HighPart;
893     if (size.u.LowPart == INVALID_FILE_SIZE) SetLastError(0);
894     return size.u.LowPart;
895 }
896
897
898 /***********************************************************************
899  *           GetFileSizeEx   (KERNEL32.@)
900  *
901  * Retrieve the size of a file.
902  *
903  * PARAMS
904  *  hFile        [I] File to retrieve size of.
905  *  lpFileSIze   [O] On return, the size of the file.
906  *
907  * RETURNS
908  *  Success: TRUE.
909  *  Failure: FALSE, check GetLastError().
910  */
911 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
912 {
913     FILE_STANDARD_INFORMATION info;
914     IO_STATUS_BLOCK io;
915     NTSTATUS status;
916
917     status = NtQueryInformationFile( hFile, &io, &info, sizeof(info), FileStandardInformation );
918     if (status == STATUS_SUCCESS)
919     {
920         *lpFileSize = info.EndOfFile;
921         return TRUE;
922     }
923     SetLastError( RtlNtStatusToDosError(status) );
924     return FALSE;
925 }
926
927
928 /**************************************************************************
929  *           SetEndOfFile   (KERNEL32.@)
930  *
931  * Sets the current position as the end of the file.
932  *
933  * PARAMS
934  *  hFile [I] File handle.
935  *
936  * RETURNS
937  *  Success: TRUE.
938  *  Failure: FALSE, check GetLastError().
939  */
940 BOOL WINAPI SetEndOfFile( HANDLE hFile )
941 {
942     FILE_POSITION_INFORMATION pos;
943     FILE_END_OF_FILE_INFORMATION eof;
944     IO_STATUS_BLOCK io;
945     NTSTATUS status;
946
947     status = NtQueryInformationFile( hFile, &io, &pos, sizeof(pos), FilePositionInformation );
948     if (status == STATUS_SUCCESS)
949     {
950         eof.EndOfFile = pos.CurrentByteOffset;
951         status = NtSetInformationFile( hFile, &io, &eof, sizeof(eof), FileEndOfFileInformation );
952     }
953     if (status == STATUS_SUCCESS) return TRUE;
954     SetLastError( RtlNtStatusToDosError(status) );
955     return FALSE;
956 }
957
958
959 /***********************************************************************
960  *           SetFilePointer   (KERNEL32.@)
961  */
962 DWORD WINAPI SetFilePointer( HANDLE hFile, LONG distance, LONG *highword, DWORD method )
963 {
964     LARGE_INTEGER dist, newpos;
965
966     if (highword)
967     {
968         dist.u.LowPart  = distance;
969         dist.u.HighPart = *highword;
970     }
971     else dist.QuadPart = distance;
972
973     if (!SetFilePointerEx( hFile, dist, &newpos, method )) return INVALID_SET_FILE_POINTER;
974
975     if (highword) *highword = newpos.u.HighPart;
976     if (newpos.u.LowPart == INVALID_SET_FILE_POINTER) SetLastError( 0 );
977     return newpos.u.LowPart;
978 }
979
980
981 /***********************************************************************
982  *           SetFilePointerEx   (KERNEL32.@)
983  */
984 BOOL WINAPI SetFilePointerEx( HANDLE hFile, LARGE_INTEGER distance,
985                               LARGE_INTEGER *newpos, DWORD method )
986 {
987     LONGLONG pos;
988     IO_STATUS_BLOCK io;
989     FILE_POSITION_INFORMATION info;
990
991     switch(method)
992     {
993     case FILE_BEGIN:
994         pos = distance.QuadPart;
995         break;
996     case FILE_CURRENT:
997         if (NtQueryInformationFile( hFile, &io, &info, sizeof(info), FilePositionInformation ))
998             goto error;
999         pos = info.CurrentByteOffset.QuadPart + distance.QuadPart;
1000         break;
1001     case FILE_END:
1002         {
1003             FILE_END_OF_FILE_INFORMATION eof;
1004             if (NtQueryInformationFile( hFile, &io, &eof, sizeof(eof), FileEndOfFileInformation ))
1005                 goto error;
1006             pos = eof.EndOfFile.QuadPart + distance.QuadPart;
1007         }
1008         break;
1009     default:
1010         SetLastError( ERROR_INVALID_PARAMETER );
1011         return FALSE;
1012     }
1013
1014     if (pos < 0)
1015     {
1016         SetLastError( ERROR_NEGATIVE_SEEK );
1017         return FALSE;
1018     }
1019
1020     info.CurrentByteOffset.QuadPart = pos;
1021     if (NtSetInformationFile( hFile, &io, &info, sizeof(info), FilePositionInformation ))
1022         goto error;
1023     if (newpos) newpos->QuadPart = pos;
1024     return TRUE;
1025
1026 error:
1027     SetLastError( RtlNtStatusToDosError(io.u.Status) );
1028     return FALSE;
1029 }
1030
1031 /***********************************************************************
1032  *           GetFileTime   (KERNEL32.@)
1033  */
1034 BOOL WINAPI GetFileTime( HANDLE hFile, FILETIME *lpCreationTime,
1035                          FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime )
1036 {
1037     FILE_BASIC_INFORMATION info;
1038     IO_STATUS_BLOCK io;
1039     NTSTATUS status;
1040
1041     status = NtQueryInformationFile( hFile, &io, &info, sizeof(info), FileBasicInformation );
1042     if (status == STATUS_SUCCESS)
1043     {
1044         if (lpCreationTime)
1045         {
1046             lpCreationTime->dwHighDateTime = info.CreationTime.u.HighPart;
1047             lpCreationTime->dwLowDateTime  = info.CreationTime.u.LowPart;
1048         }
1049         if (lpLastAccessTime)
1050         {
1051             lpLastAccessTime->dwHighDateTime = info.LastAccessTime.u.HighPart;
1052             lpLastAccessTime->dwLowDateTime  = info.LastAccessTime.u.LowPart;
1053         }
1054         if (lpLastWriteTime)
1055         {
1056             lpLastWriteTime->dwHighDateTime = info.LastWriteTime.u.HighPart;
1057             lpLastWriteTime->dwLowDateTime  = info.LastWriteTime.u.LowPart;
1058         }
1059         return TRUE;
1060     }
1061     SetLastError( RtlNtStatusToDosError(status) );
1062     return FALSE;
1063 }
1064
1065
1066 /***********************************************************************
1067  *              SetFileTime   (KERNEL32.@)
1068  */
1069 BOOL WINAPI SetFileTime( HANDLE hFile, const FILETIME *ctime,
1070                          const FILETIME *atime, const FILETIME *mtime )
1071 {
1072     FILE_BASIC_INFORMATION info;
1073     IO_STATUS_BLOCK io;
1074     NTSTATUS status;
1075
1076     memset( &info, 0, sizeof(info) );
1077     if (ctime)
1078     {
1079         info.CreationTime.u.HighPart = ctime->dwHighDateTime;
1080         info.CreationTime.u.LowPart  = ctime->dwLowDateTime;
1081     }
1082     if (atime)
1083     {
1084         info.LastAccessTime.u.HighPart = atime->dwHighDateTime;
1085         info.LastAccessTime.u.LowPart  = atime->dwLowDateTime;
1086     }
1087     if (mtime)
1088     {
1089         info.LastWriteTime.u.HighPart = mtime->dwHighDateTime;
1090         info.LastWriteTime.u.LowPart  = mtime->dwLowDateTime;
1091     }
1092
1093     status = NtSetInformationFile( hFile, &io, &info, sizeof(info), FileBasicInformation );
1094     if (status == STATUS_SUCCESS) return TRUE;
1095     SetLastError( RtlNtStatusToDosError(status) );
1096     return FALSE;
1097 }
1098
1099
1100 /**************************************************************************
1101  *           LockFile   (KERNEL32.@)
1102  */
1103 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
1104                       DWORD count_low, DWORD count_high )
1105 {
1106     NTSTATUS            status;
1107     LARGE_INTEGER       count, offset;
1108
1109     TRACE( "%p %x%08x %x%08x\n",
1110            hFile, offset_high, offset_low, count_high, count_low );
1111
1112     count.u.LowPart = count_low;
1113     count.u.HighPart = count_high;
1114     offset.u.LowPart = offset_low;
1115     offset.u.HighPart = offset_high;
1116
1117     status = NtLockFile( hFile, 0, NULL, NULL,
1118                          NULL, &offset, &count, NULL, TRUE, TRUE );
1119
1120     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
1121     return !status;
1122 }
1123
1124
1125 /**************************************************************************
1126  * LockFileEx [KERNEL32.@]
1127  *
1128  * Locks a byte range within an open file for shared or exclusive access.
1129  *
1130  * RETURNS
1131  *   success: TRUE
1132  *   failure: FALSE
1133  *
1134  * NOTES
1135  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
1136  */
1137 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
1138                         DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
1139 {
1140     NTSTATUS status;
1141     LARGE_INTEGER count, offset;
1142     LPVOID   cvalue = NULL;
1143
1144     if (reserved)
1145     {
1146         SetLastError( ERROR_INVALID_PARAMETER );
1147         return FALSE;
1148     }
1149
1150     TRACE( "%p %x%08x %x%08x flags %x\n",
1151            hFile, overlapped->u.s.OffsetHigh, overlapped->u.s.Offset, 
1152            count_high, count_low, flags );
1153
1154     count.u.LowPart = count_low;
1155     count.u.HighPart = count_high;
1156     offset.u.LowPart = overlapped->u.s.Offset;
1157     offset.u.HighPart = overlapped->u.s.OffsetHigh;
1158
1159     if (((ULONG_PTR)overlapped->hEvent & 1) == 0) cvalue = overlapped;
1160
1161     status = NtLockFile( hFile, overlapped->hEvent, NULL, cvalue,
1162                          NULL, &offset, &count, NULL,
1163                          flags & LOCKFILE_FAIL_IMMEDIATELY,
1164                          flags & LOCKFILE_EXCLUSIVE_LOCK );
1165
1166     if (status) SetLastError( RtlNtStatusToDosError(status) );
1167     return !status;
1168 }
1169
1170
1171 /**************************************************************************
1172  *           UnlockFile   (KERNEL32.@)
1173  */
1174 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
1175                         DWORD count_low, DWORD count_high )
1176 {
1177     NTSTATUS    status;
1178     LARGE_INTEGER count, offset;
1179
1180     count.u.LowPart = count_low;
1181     count.u.HighPart = count_high;
1182     offset.u.LowPart = offset_low;
1183     offset.u.HighPart = offset_high;
1184
1185     status = NtUnlockFile( hFile, NULL, &offset, &count, NULL);
1186     if (status) SetLastError( RtlNtStatusToDosError(status) );
1187     return !status;
1188 }
1189
1190
1191 /**************************************************************************
1192  *           UnlockFileEx   (KERNEL32.@)
1193  */
1194 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
1195                           LPOVERLAPPED overlapped )
1196 {
1197     if (reserved)
1198     {
1199         SetLastError( ERROR_INVALID_PARAMETER );
1200         return FALSE;
1201     }
1202     if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n");
1203
1204     return UnlockFile( hFile, overlapped->u.s.Offset, overlapped->u.s.OffsetHigh, count_low, count_high );
1205 }
1206
1207
1208 /***********************************************************************
1209  *           Win32HandleToDosFileHandle   (KERNEL32.21)
1210  *
1211  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
1212  * longer valid after this function (even on failure).
1213  *
1214  * Note: this is not exactly right, since on Win95 the Win32 handles
1215  *       are on top of DOS handles and we do it the other way
1216  *       around. Should be good enough though.
1217  */
1218 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
1219 {
1220     int i;
1221
1222     if (!handle || (handle == INVALID_HANDLE_VALUE))
1223         return HFILE_ERROR;
1224
1225     FILE_InitProcessDosHandles();
1226     for (i = 0; i < DOS_TABLE_SIZE; i++)
1227         if (!dos_handles[i])
1228         {
1229             dos_handles[i] = handle;
1230             TRACE("Got %d for h32 %p\n", i, handle );
1231             return (HFILE)i;
1232         }
1233     CloseHandle( handle );
1234     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1235     return HFILE_ERROR;
1236 }
1237
1238
1239 /***********************************************************************
1240  *           DosFileHandleToWin32Handle   (KERNEL32.20)
1241  *
1242  * Return the Win32 handle for a DOS handle.
1243  *
1244  * Note: this is not exactly right, since on Win95 the Win32 handles
1245  *       are on top of DOS handles and we do it the other way
1246  *       around. Should be good enough though.
1247  */
1248 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
1249 {
1250     HFILE16 hfile = (HFILE16)handle;
1251     if (hfile < 5) FILE_InitProcessDosHandles();
1252     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
1253     {
1254         SetLastError( ERROR_INVALID_HANDLE );
1255         return INVALID_HANDLE_VALUE;
1256     }
1257     return dos_handles[hfile];
1258 }
1259
1260
1261 /*************************************************************************
1262  *           SetHandleCount   (KERNEL32.@)
1263  */
1264 UINT WINAPI SetHandleCount( UINT count )
1265 {
1266     return min( 256, count );
1267 }
1268
1269
1270 /***********************************************************************
1271  *           DisposeLZ32Handle   (KERNEL32.22)
1272  *
1273  * Note: this is not entirely correct, we should only close the
1274  *       32-bit handle and not the 16-bit one, but we cannot do
1275  *       this because of the way our DOS handles are implemented.
1276  *       It shouldn't break anything though.
1277  */
1278 void WINAPI DisposeLZ32Handle( HANDLE handle )
1279 {
1280     int i;
1281
1282     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
1283
1284     for (i = 5; i < DOS_TABLE_SIZE; i++)
1285         if (dos_handles[i] == handle)
1286         {
1287             dos_handles[i] = 0;
1288             CloseHandle( handle );
1289             break;
1290         }
1291 }
1292
1293 /**************************************************************************
1294  *                      Operations on file names                          *
1295  **************************************************************************/
1296
1297
1298 /*************************************************************************
1299  * CreateFileW [KERNEL32.@]  Creates or opens a file or other object
1300  *
1301  * Creates or opens an object, and returns a handle that can be used to
1302  * access that object.
1303  *
1304  * PARAMS
1305  *
1306  * filename     [in] pointer to filename to be accessed
1307  * access       [in] access mode requested
1308  * sharing      [in] share mode
1309  * sa           [in] pointer to security attributes
1310  * creation     [in] how to create the file
1311  * attributes   [in] attributes for newly created file
1312  * template     [in] handle to file with extended attributes to copy
1313  *
1314  * RETURNS
1315  *   Success: Open handle to specified file
1316  *   Failure: INVALID_HANDLE_VALUE
1317  */
1318 HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
1319                               LPSECURITY_ATTRIBUTES sa, DWORD creation,
1320                               DWORD attributes, HANDLE template )
1321 {
1322     NTSTATUS status;
1323     UINT options;
1324     OBJECT_ATTRIBUTES attr;
1325     UNICODE_STRING nameW;
1326     IO_STATUS_BLOCK io;
1327     HANDLE ret;
1328     DWORD dosdev;
1329     const WCHAR *vxd_name = NULL;
1330     static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0};
1331     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
1332     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
1333     SECURITY_QUALITY_OF_SERVICE qos;
1334
1335     static const UINT nt_disposition[5] =
1336     {
1337         FILE_CREATE,        /* CREATE_NEW */
1338         FILE_OVERWRITE_IF,  /* CREATE_ALWAYS */
1339         FILE_OPEN,          /* OPEN_EXISTING */
1340         FILE_OPEN_IF,       /* OPEN_ALWAYS */
1341         FILE_OVERWRITE      /* TRUNCATE_EXISTING */
1342     };
1343
1344
1345     /* sanity checks */
1346
1347     if (!filename || !filename[0])
1348     {
1349         SetLastError( ERROR_PATH_NOT_FOUND );
1350         return INVALID_HANDLE_VALUE;
1351     }
1352
1353     TRACE("%s %s%s%s%s%s%s creation %d attributes 0x%x\n", debugstr_w(filename),
1354           (access & GENERIC_READ)?"GENERIC_READ ":"",
1355           (access & GENERIC_WRITE)?"GENERIC_WRITE ":"",
1356           (!access)?"QUERY_ACCESS ":"",
1357           (sharing & FILE_SHARE_READ)?"FILE_SHARE_READ ":"",
1358           (sharing & FILE_SHARE_WRITE)?"FILE_SHARE_WRITE ":"",
1359           (sharing & FILE_SHARE_DELETE)?"FILE_SHARE_DELETE ":"",
1360           creation, attributes);
1361
1362     /* Open a console for CONIN$ or CONOUT$ */
1363
1364     if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
1365     {
1366         ret = OpenConsoleW(filename, access, (sa && sa->bInheritHandle), creation);
1367         goto done;
1368     }
1369
1370     if (!strncmpW(filename, bkslashes_with_dotW, 4))
1371     {
1372         static const WCHAR pipeW[] = {'P','I','P','E','\\',0};
1373         static const WCHAR mailslotW[] = {'M','A','I','L','S','L','O','T','\\',0};
1374
1375         if ((isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0') ||
1376             !strncmpiW( filename + 4, pipeW, 5 ) ||
1377             !strncmpiW( filename + 4, mailslotW, 9 ))
1378         {
1379             dosdev = 0;
1380         }
1381         else if ((dosdev = RtlIsDosDeviceName_U( filename + 4 )))
1382         {
1383             dosdev += MAKELONG( 0, 4*sizeof(WCHAR) );  /* adjust position to start of filename */
1384         }
1385         else if (GetVersion() & 0x80000000)
1386         {
1387             vxd_name = filename + 4;
1388         }
1389     }
1390     else dosdev = RtlIsDosDeviceName_U( filename );
1391
1392     if (dosdev)
1393     {
1394         static const WCHAR conW[] = {'C','O','N'};
1395
1396         if (LOWORD(dosdev) == sizeof(conW) &&
1397             !memicmpW( filename + HIWORD(dosdev)/sizeof(WCHAR), conW, sizeof(conW)/sizeof(WCHAR)))
1398         {
1399             switch (access & (GENERIC_READ|GENERIC_WRITE))
1400             {
1401             case GENERIC_READ:
1402                 ret = OpenConsoleW(coninW, access, (sa && sa->bInheritHandle), creation);
1403                 goto done;
1404             case GENERIC_WRITE:
1405                 ret = OpenConsoleW(conoutW, access, (sa && sa->bInheritHandle), creation);
1406                 goto done;
1407             default:
1408                 SetLastError( ERROR_FILE_NOT_FOUND );
1409                 return INVALID_HANDLE_VALUE;
1410             }
1411         }
1412     }
1413
1414     if (creation < CREATE_NEW || creation > TRUNCATE_EXISTING)
1415     {
1416         SetLastError( ERROR_INVALID_PARAMETER );
1417         return INVALID_HANDLE_VALUE;
1418     }
1419
1420     if (!RtlDosPathNameToNtPathName_U( filename, &nameW, NULL, NULL ))
1421     {
1422         SetLastError( ERROR_PATH_NOT_FOUND );
1423         return INVALID_HANDLE_VALUE;
1424     }
1425
1426     /* now call NtCreateFile */
1427
1428     options = 0;
1429     if (attributes & FILE_FLAG_BACKUP_SEMANTICS)
1430         options |= FILE_OPEN_FOR_BACKUP_INTENT;
1431     else
1432         options |= FILE_NON_DIRECTORY_FILE;
1433     if (attributes & FILE_FLAG_DELETE_ON_CLOSE)
1434     {
1435         options |= FILE_DELETE_ON_CLOSE;
1436         access |= DELETE;
1437     }
1438     if (attributes & FILE_FLAG_NO_BUFFERING)
1439         options |= FILE_NO_INTERMEDIATE_BUFFERING;
1440     if (!(attributes & FILE_FLAG_OVERLAPPED))
1441         options |= FILE_SYNCHRONOUS_IO_ALERT;
1442     if (attributes & FILE_FLAG_RANDOM_ACCESS)
1443         options |= FILE_RANDOM_ACCESS;
1444     attributes &= FILE_ATTRIBUTE_VALID_FLAGS;
1445
1446     attr.Length = sizeof(attr);
1447     attr.RootDirectory = 0;
1448     attr.Attributes = OBJ_CASE_INSENSITIVE;
1449     attr.ObjectName = &nameW;
1450     attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL;
1451     if (attributes & SECURITY_SQOS_PRESENT)
1452     {
1453         qos.Length = sizeof(qos);
1454         qos.ImpersonationLevel = (attributes >> 16) & 0x3;
1455         qos.ContextTrackingMode = attributes & SECURITY_CONTEXT_TRACKING ? SECURITY_DYNAMIC_TRACKING : SECURITY_STATIC_TRACKING;
1456         qos.EffectiveOnly = attributes & SECURITY_EFFECTIVE_ONLY ? TRUE : FALSE;
1457         attr.SecurityQualityOfService = &qos;
1458     }
1459     else
1460         attr.SecurityQualityOfService = NULL;
1461
1462     if (sa && sa->bInheritHandle) attr.Attributes |= OBJ_INHERIT;
1463
1464     status = NtCreateFile( &ret, access, &attr, &io, NULL, attributes,
1465                            sharing, nt_disposition[creation - CREATE_NEW],
1466                            options, NULL, 0 );
1467     if (status)
1468     {
1469         if (vxd_name && vxd_name[0] && (ret = VXD_Open( vxd_name, access, sa ))) goto done;
1470
1471         WARN("Unable to create file %s (status %x)\n", debugstr_w(filename), status);
1472         ret = INVALID_HANDLE_VALUE;
1473
1474         /* In the case file creation was rejected due to CREATE_NEW flag
1475          * was specified and file with that name already exists, correct
1476          * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
1477          * Note: RtlNtStatusToDosError is not the subject to blame here.
1478          */
1479         if (status == STATUS_OBJECT_NAME_COLLISION)
1480             SetLastError( ERROR_FILE_EXISTS );
1481         else
1482             SetLastError( RtlNtStatusToDosError(status) );
1483     }
1484     else
1485     {
1486         if ((creation == CREATE_ALWAYS && io.Information == FILE_OVERWRITTEN) ||
1487             (creation == OPEN_ALWAYS && io.Information == FILE_OPENED))
1488             SetLastError( ERROR_ALREADY_EXISTS );
1489         else
1490             SetLastError( 0 );
1491     }
1492     RtlFreeUnicodeString( &nameW );
1493
1494  done:
1495     if (!ret) ret = INVALID_HANDLE_VALUE;
1496     TRACE("returning %p\n", ret);
1497     return ret;
1498 }
1499
1500
1501
1502 /*************************************************************************
1503  *              CreateFileA              (KERNEL32.@)
1504  *
1505  * See CreateFileW.
1506  */
1507 HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
1508                            LPSECURITY_ATTRIBUTES sa, DWORD creation,
1509                            DWORD attributes, HANDLE template)
1510 {
1511     WCHAR *nameW;
1512
1513     if (!(nameW = FILE_name_AtoW( filename, FALSE ))) return INVALID_HANDLE_VALUE;
1514     return CreateFileW( nameW, access, sharing, sa, creation, attributes, template );
1515 }
1516
1517
1518 /***********************************************************************
1519  *           DeleteFileW   (KERNEL32.@)
1520  *
1521  * Delete a file.
1522  *
1523  * PARAMS
1524  *  path [I] Path to the file to delete.
1525  *
1526  * RETURNS
1527  *  Success: TRUE.
1528  *  Failure: FALSE, check GetLastError().
1529  */
1530 BOOL WINAPI DeleteFileW( LPCWSTR path )
1531 {
1532     UNICODE_STRING nameW;
1533     OBJECT_ATTRIBUTES attr;
1534     NTSTATUS status;
1535     HANDLE hFile;
1536     IO_STATUS_BLOCK io;
1537
1538     TRACE("%s\n", debugstr_w(path) );
1539
1540     if (!RtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ))
1541     {
1542         SetLastError( ERROR_PATH_NOT_FOUND );
1543         return FALSE;
1544     }
1545
1546     attr.Length = sizeof(attr);
1547     attr.RootDirectory = 0;
1548     attr.Attributes = OBJ_CASE_INSENSITIVE;
1549     attr.ObjectName = &nameW;
1550     attr.SecurityDescriptor = NULL;
1551     attr.SecurityQualityOfService = NULL;
1552
1553     status = NtCreateFile(&hFile, GENERIC_READ | GENERIC_WRITE | DELETE,
1554                           &attr, &io, NULL, 0,
1555                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1556                           FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0);
1557     if (status == STATUS_SUCCESS) status = NtClose(hFile);
1558
1559     RtlFreeUnicodeString( &nameW );
1560     if (status)
1561     {
1562         SetLastError( RtlNtStatusToDosError(status) );
1563         return FALSE;
1564     }
1565     return TRUE;
1566 }
1567
1568
1569 /***********************************************************************
1570  *           DeleteFileA   (KERNEL32.@)
1571  *
1572  * See DeleteFileW.
1573  */
1574 BOOL WINAPI DeleteFileA( LPCSTR path )
1575 {
1576     WCHAR *pathW;
1577
1578     if (!(pathW = FILE_name_AtoW( path, FALSE ))) return FALSE;
1579     return DeleteFileW( pathW );
1580 }
1581
1582
1583 /**************************************************************************
1584  *           ReplaceFileW   (KERNEL32.@)
1585  *           ReplaceFile    (KERNEL32.@)
1586  */
1587 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName,
1588                          LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
1589                          LPVOID lpExclude, LPVOID lpReserved)
1590 {
1591     UNICODE_STRING nt_replaced_name, nt_replacement_name;
1592     ANSI_STRING unix_replaced_name, unix_replacement_name, unix_backup_name;
1593     HANDLE hReplaced = NULL, hReplacement = NULL, hBackup = NULL;
1594     DWORD error = ERROR_SUCCESS;
1595     UINT replaced_flags;
1596     BOOL ret = FALSE;
1597     NTSTATUS status;
1598     IO_STATUS_BLOCK io;
1599     OBJECT_ATTRIBUTES attr;
1600
1601     if (dwReplaceFlags)
1602         FIXME("Ignoring flags %x\n", dwReplaceFlags);
1603
1604     /* First two arguments are mandatory */
1605     if (!lpReplacedFileName || !lpReplacementFileName)
1606     {
1607         SetLastError(ERROR_INVALID_PARAMETER);
1608         return FALSE;
1609     }
1610
1611     unix_replaced_name.Buffer = NULL;
1612     unix_replacement_name.Buffer = NULL;
1613     unix_backup_name.Buffer = NULL;
1614
1615     attr.Length = sizeof(attr);
1616     attr.RootDirectory = 0;
1617     attr.Attributes = OBJ_CASE_INSENSITIVE;
1618     attr.ObjectName = NULL;
1619     attr.SecurityDescriptor = NULL;
1620     attr.SecurityQualityOfService = NULL;
1621
1622     /* Open the "replaced" file for reading and writing */
1623     if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &nt_replaced_name, NULL, NULL)))
1624     {
1625         error = ERROR_PATH_NOT_FOUND;
1626         goto fail;
1627     }
1628     replaced_flags = lpBackupFileName ? FILE_OPEN : FILE_OPEN_IF;
1629     attr.ObjectName = &nt_replaced_name;
1630     status = NtOpenFile(&hReplaced, GENERIC_READ|GENERIC_WRITE|DELETE|SYNCHRONIZE,
1631                         &attr, &io,
1632                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1633                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
1634     if (status == STATUS_SUCCESS)
1635         status = wine_nt_to_unix_file_name(&nt_replaced_name, &unix_replaced_name, replaced_flags, FALSE);
1636     RtlFreeUnicodeString(&nt_replaced_name);
1637     if (status != STATUS_SUCCESS)
1638     {
1639         if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1640             error = ERROR_FILE_NOT_FOUND;
1641         else
1642             error = ERROR_UNABLE_TO_REMOVE_REPLACED;
1643         goto fail;
1644     }
1645
1646     /*
1647      * Open the replacement file for reading, writing, and deleting
1648      * (writing and deleting are needed when finished)
1649      */
1650     if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &nt_replacement_name, NULL, NULL)))
1651     {
1652         error = ERROR_PATH_NOT_FOUND;
1653         goto fail;
1654     }
1655     attr.ObjectName = &nt_replacement_name;
1656     status = NtOpenFile(&hReplacement,
1657                         GENERIC_READ|GENERIC_WRITE|DELETE|WRITE_DAC|SYNCHRONIZE,
1658                         &attr, &io, 0,
1659                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
1660     if (status == STATUS_SUCCESS)
1661         status = wine_nt_to_unix_file_name(&nt_replacement_name, &unix_replacement_name, FILE_OPEN, FALSE);
1662     RtlFreeUnicodeString(&nt_replacement_name);
1663     if (status != STATUS_SUCCESS)
1664     {
1665         error = RtlNtStatusToDosError(status);
1666         goto fail;
1667     }
1668
1669     /* If the user wants a backup then that needs to be performed first */
1670     if (lpBackupFileName)
1671     {
1672         UNICODE_STRING nt_backup_name;
1673         FILE_BASIC_INFORMATION replaced_info;
1674
1675         /* Obtain the file attributes from the "replaced" file */
1676         status = NtQueryInformationFile(hReplaced, &io, &replaced_info,
1677                                         sizeof(replaced_info),
1678                                         FileBasicInformation);
1679         if (status != STATUS_SUCCESS)
1680         {
1681             error = RtlNtStatusToDosError(status);
1682             goto fail;
1683         }
1684
1685         if (!(RtlDosPathNameToNtPathName_U(lpBackupFileName, &nt_backup_name, NULL, NULL)))
1686         {
1687             error = ERROR_PATH_NOT_FOUND;
1688             goto fail;
1689         }
1690         attr.ObjectName = &nt_backup_name;
1691         /* Open the backup with permissions to write over it */
1692         status = NtCreateFile(&hBackup, GENERIC_WRITE,
1693                               &attr, &io, NULL, replaced_info.FileAttributes,
1694                               FILE_SHARE_WRITE, FILE_OPEN_IF,
1695                               FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE,
1696                               NULL, 0);
1697         if (status == STATUS_SUCCESS)
1698             status = wine_nt_to_unix_file_name(&nt_backup_name, &unix_backup_name, FILE_OPEN_IF, FALSE);
1699         if (status != STATUS_SUCCESS)
1700         {
1701             error = RtlNtStatusToDosError(status);
1702             goto fail;
1703         }
1704
1705         /* If an existing backup exists then copy over it */
1706         if (rename(unix_replaced_name.Buffer, unix_backup_name.Buffer) == -1)
1707         {
1708             error = ERROR_UNABLE_TO_REMOVE_REPLACED; /* is this correct? */
1709             goto fail;
1710         }
1711     }
1712
1713     /*
1714      * Now that the backup has been performed (if requested), copy the replacement
1715      * into place
1716      */
1717     if (rename(unix_replacement_name.Buffer, unix_replaced_name.Buffer) == -1)
1718     {
1719         if (errno == EACCES)
1720         {
1721             /* Inappropriate permissions on "replaced", rename will fail */
1722             error = ERROR_UNABLE_TO_REMOVE_REPLACED;
1723             goto fail;
1724         }
1725         /* on failure we need to indicate whether a backup was made */
1726         if (!lpBackupFileName)
1727             error = ERROR_UNABLE_TO_MOVE_REPLACEMENT;
1728         else
1729             error = ERROR_UNABLE_TO_MOVE_REPLACEMENT_2;
1730         goto fail;
1731     }
1732     /* Success! */
1733     ret = TRUE;
1734
1735     /* Perform resource cleanup */
1736 fail:
1737     if (hBackup) CloseHandle(hBackup);
1738     if (hReplaced) CloseHandle(hReplaced);
1739     if (hReplacement) CloseHandle(hReplacement);
1740     RtlFreeAnsiString(&unix_backup_name);
1741     RtlFreeAnsiString(&unix_replacement_name);
1742     RtlFreeAnsiString(&unix_replaced_name);
1743
1744     /* If there was an error, set the error code */
1745     if(!ret)
1746         SetLastError(error);
1747     return ret;
1748 }
1749
1750
1751 /**************************************************************************
1752  *           ReplaceFileA (KERNEL32.@)
1753  */
1754 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
1755                          LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
1756                          LPVOID lpExclude, LPVOID lpReserved)
1757 {
1758     WCHAR *replacedW, *replacementW, *backupW = NULL;
1759     BOOL ret;
1760
1761     /* This function only makes sense when the first two parameters are defined */
1762     if (!lpReplacedFileName || !(replacedW = FILE_name_AtoW( lpReplacedFileName, TRUE )))
1763     {
1764         SetLastError(ERROR_INVALID_PARAMETER);
1765         return FALSE;
1766     }
1767     if (!lpReplacementFileName || !(replacementW = FILE_name_AtoW( lpReplacementFileName, TRUE )))
1768     {
1769         HeapFree( GetProcessHeap(), 0, replacedW );
1770         SetLastError(ERROR_INVALID_PARAMETER);
1771         return FALSE;
1772     }
1773     /* The backup parameter, however, is optional */
1774     if (lpBackupFileName)
1775     {
1776         if (!(backupW = FILE_name_AtoW( lpBackupFileName, TRUE )))
1777         {
1778             HeapFree( GetProcessHeap(), 0, replacedW );
1779             HeapFree( GetProcessHeap(), 0, replacementW );
1780             SetLastError(ERROR_INVALID_PARAMETER);
1781             return FALSE;
1782         }
1783     }
1784     ret = ReplaceFileW( replacedW, replacementW, backupW, dwReplaceFlags, lpExclude, lpReserved );
1785     HeapFree( GetProcessHeap(), 0, replacedW );
1786     HeapFree( GetProcessHeap(), 0, replacementW );
1787     HeapFree( GetProcessHeap(), 0, backupW );
1788     return ret;
1789 }
1790
1791
1792 /*************************************************************************
1793  *           FindFirstFileExW  (KERNEL32.@)
1794  *
1795  * NOTE: The FindExSearchLimitToDirectories is ignored - it gives the same
1796  * results as FindExSearchNameMatch
1797  */
1798 HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
1799                                 LPVOID data, FINDEX_SEARCH_OPS search_op,
1800                                 LPVOID filter, DWORD flags)
1801 {
1802     WCHAR *mask, *p;
1803     FIND_FIRST_INFO *info = NULL;
1804     UNICODE_STRING nt_name;
1805     OBJECT_ATTRIBUTES attr;
1806     IO_STATUS_BLOCK io;
1807     NTSTATUS status;
1808     DWORD device = 0;
1809
1810     TRACE("%s %d %p %d %p %x\n", debugstr_w(filename), level, data, search_op, filter, flags);
1811
1812     if ((search_op != FindExSearchNameMatch && search_op != FindExSearchLimitToDirectories)
1813         || flags != 0)
1814     {
1815         FIXME("options not implemented 0x%08x 0x%08x\n", search_op, flags );
1816         return INVALID_HANDLE_VALUE;
1817     }
1818     if (level != FindExInfoStandard)
1819     {
1820         FIXME("info level %d not implemented\n", level );
1821         return INVALID_HANDLE_VALUE;
1822     }
1823
1824     if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, &mask, NULL ))
1825     {
1826         SetLastError( ERROR_PATH_NOT_FOUND );
1827         return INVALID_HANDLE_VALUE;
1828     }
1829
1830     if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info))))
1831     {
1832         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1833         goto error;
1834     }
1835
1836     if (!mask && (device = RtlIsDosDeviceName_U( filename )))
1837     {
1838         static const WCHAR dotW[] = {'.',0};
1839         WCHAR *dir = NULL;
1840
1841         /* we still need to check that the directory can be opened */
1842
1843         if (HIWORD(device))
1844         {
1845             if (!(dir = HeapAlloc( GetProcessHeap(), 0, HIWORD(device) + sizeof(WCHAR) )))
1846             {
1847                 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1848                 goto error;
1849             }
1850             memcpy( dir, filename, HIWORD(device) );
1851             dir[HIWORD(device)/sizeof(WCHAR)] = 0;
1852         }
1853         RtlFreeUnicodeString( &nt_name );
1854         if (!RtlDosPathNameToNtPathName_U( dir ? dir : dotW, &nt_name, &mask, NULL ))
1855         {
1856             HeapFree( GetProcessHeap(), 0, dir );
1857             SetLastError( ERROR_PATH_NOT_FOUND );
1858             goto error;
1859         }
1860         HeapFree( GetProcessHeap(), 0, dir );
1861         RtlInitUnicodeString( &info->mask, NULL );
1862     }
1863     else if (!mask || !*mask)
1864     {
1865         SetLastError( ERROR_FILE_NOT_FOUND );
1866         goto error;
1867     }
1868     else
1869     {
1870         if (!RtlCreateUnicodeString( &info->mask, mask ))
1871         {
1872             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1873             goto error;
1874         }
1875
1876         /* truncate dir name before mask */
1877         *mask = 0;
1878         nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
1879     }
1880
1881     /* check if path is the root of the drive */
1882     info->is_root = FALSE;
1883     p = nt_name.Buffer + 4;  /* skip \??\ prefix */
1884     if (p[0] && p[1] == ':')
1885     {
1886         p += 2;
1887         while (*p == '\\') p++;
1888         info->is_root = (*p == 0);
1889     }
1890
1891     attr.Length = sizeof(attr);
1892     attr.RootDirectory = 0;
1893     attr.Attributes = OBJ_CASE_INSENSITIVE;
1894     attr.ObjectName = &nt_name;
1895     attr.SecurityDescriptor = NULL;
1896     attr.SecurityQualityOfService = NULL;
1897
1898     status = NtOpenFile( &info->handle, GENERIC_READ, &attr, &io,
1899                          FILE_SHARE_READ | FILE_SHARE_WRITE,
1900                          FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
1901
1902     if (status != STATUS_SUCCESS)
1903     {
1904         RtlFreeUnicodeString( &info->mask );
1905         if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1906             SetLastError( ERROR_PATH_NOT_FOUND );
1907         else
1908             SetLastError( RtlNtStatusToDosError(status) );
1909         goto error;
1910     }
1911
1912     RtlInitializeCriticalSection( &info->cs );
1913     info->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FIND_FIRST_INFO.cs");
1914     info->path     = nt_name;
1915     info->magic    = FIND_FIRST_MAGIC;
1916     info->data_pos = 0;
1917     info->data_len = 0;
1918     info->search_op = search_op;
1919
1920     if (device)
1921     {
1922         WIN32_FIND_DATAW *wfd = data;
1923
1924         memset( wfd, 0, sizeof(*wfd) );
1925         memcpy( wfd->cFileName, filename + HIWORD(device)/sizeof(WCHAR), LOWORD(device) );
1926         wfd->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
1927         CloseHandle( info->handle );
1928         info->handle = 0;
1929     }
1930     else
1931     {
1932         IO_STATUS_BLOCK io;
1933
1934         NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
1935                               FileBothDirectoryInformation, FALSE, &info->mask, TRUE );
1936         if (io.u.Status)
1937         {
1938             FindClose( info );
1939             SetLastError( RtlNtStatusToDosError( io.u.Status ) );
1940             return INVALID_HANDLE_VALUE;
1941         }
1942         info->data_len = io.Information;
1943         if (!FindNextFileW( info, data ))
1944         {
1945             TRACE( "%s not found\n", debugstr_w(filename) );
1946             FindClose( info );
1947             SetLastError( ERROR_FILE_NOT_FOUND );
1948             return INVALID_HANDLE_VALUE;
1949         }
1950         if (!strpbrkW( info->mask.Buffer, wildcardsW ))
1951         {
1952             /* we can't find two files with the same name */
1953             CloseHandle( info->handle );
1954             info->handle = 0;
1955         }
1956     }
1957     return info;
1958
1959 error:
1960     HeapFree( GetProcessHeap(), 0, info );
1961     RtlFreeUnicodeString( &nt_name );
1962     return INVALID_HANDLE_VALUE;
1963 }
1964
1965
1966 /*************************************************************************
1967  *           FindNextFileW   (KERNEL32.@)
1968  */
1969 BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
1970 {
1971     FIND_FIRST_INFO *info;
1972     FILE_BOTH_DIR_INFORMATION *dir_info;
1973     BOOL ret = FALSE;
1974
1975     TRACE("%p %p\n", handle, data);
1976
1977     if (!handle || handle == INVALID_HANDLE_VALUE)
1978     {
1979         SetLastError( ERROR_INVALID_HANDLE );
1980         return ret;
1981     }
1982     info = handle;
1983     if (info->magic != FIND_FIRST_MAGIC)
1984     {
1985         SetLastError( ERROR_INVALID_HANDLE );
1986         return ret;
1987     }
1988
1989     RtlEnterCriticalSection( &info->cs );
1990
1991     if (!info->handle) SetLastError( ERROR_NO_MORE_FILES );
1992     else for (;;)
1993     {
1994         if (info->data_pos >= info->data_len)  /* need to read some more data */
1995         {
1996             IO_STATUS_BLOCK io;
1997
1998             NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
1999                                   FileBothDirectoryInformation, FALSE, &info->mask, FALSE );
2000             if (io.u.Status)
2001             {
2002                 SetLastError( RtlNtStatusToDosError( io.u.Status ) );
2003                 if (io.u.Status == STATUS_NO_MORE_FILES)
2004                 {
2005                     CloseHandle( info->handle );
2006                     info->handle = 0;
2007                 }
2008                 break;
2009             }
2010             info->data_len = io.Information;
2011             info->data_pos = 0;
2012         }
2013
2014         dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
2015
2016         if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset;
2017         else info->data_pos = info->data_len;
2018
2019         /* don't return '.' and '..' in the root of the drive */
2020         if (info->is_root)
2021         {
2022             if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue;
2023             if (dir_info->FileNameLength == 2 * sizeof(WCHAR) &&
2024                 dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue;
2025         }
2026
2027         /* check for dir symlink */
2028         if ((dir_info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
2029             (dir_info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
2030             strpbrkW( info->mask.Buffer, wildcardsW ))
2031         {
2032             if (!check_dir_symlink( info, dir_info )) continue;
2033         }
2034
2035         data->dwFileAttributes = dir_info->FileAttributes;
2036         data->ftCreationTime   = *(FILETIME *)&dir_info->CreationTime;
2037         data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
2038         data->ftLastWriteTime  = *(FILETIME *)&dir_info->LastWriteTime;
2039         data->nFileSizeHigh    = dir_info->EndOfFile.QuadPart >> 32;
2040         data->nFileSizeLow     = (DWORD)dir_info->EndOfFile.QuadPart;
2041         data->dwReserved0      = 0;
2042         data->dwReserved1      = 0;
2043
2044         memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
2045         data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
2046         memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
2047         data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0;
2048
2049         TRACE("returning %s (%s)\n",
2050               debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) );
2051
2052         ret = TRUE;
2053         break;
2054     }
2055
2056     RtlLeaveCriticalSection( &info->cs );
2057     return ret;
2058 }
2059
2060
2061 /*************************************************************************
2062  *           FindClose   (KERNEL32.@)
2063  */
2064 BOOL WINAPI FindClose( HANDLE handle )
2065 {
2066     FIND_FIRST_INFO *info = handle;
2067
2068     if (!handle || handle == INVALID_HANDLE_VALUE)
2069     {
2070         SetLastError( ERROR_INVALID_HANDLE );
2071         return FALSE;
2072     }
2073
2074     __TRY
2075     {
2076         if (info->magic == FIND_FIRST_MAGIC)
2077         {
2078             RtlEnterCriticalSection( &info->cs );
2079             if (info->magic == FIND_FIRST_MAGIC)  /* in case someone else freed it in the meantime */
2080             {
2081                 info->magic = 0;
2082                 if (info->handle) CloseHandle( info->handle );
2083                 info->handle = 0;
2084                 RtlFreeUnicodeString( &info->mask );
2085                 info->mask.Buffer = NULL;
2086                 RtlFreeUnicodeString( &info->path );
2087                 info->data_pos = 0;
2088                 info->data_len = 0;
2089                 RtlLeaveCriticalSection( &info->cs );
2090                 info->cs.DebugInfo->Spare[0] = 0;
2091                 RtlDeleteCriticalSection( &info->cs );
2092                 HeapFree( GetProcessHeap(), 0, info );
2093             }
2094         }
2095     }
2096     __EXCEPT_PAGE_FAULT
2097     {
2098         WARN("Illegal handle %p\n", handle);
2099         SetLastError( ERROR_INVALID_HANDLE );
2100         return FALSE;
2101     }
2102     __ENDTRY
2103
2104     return TRUE;
2105 }
2106
2107
2108 /*************************************************************************
2109  *           FindFirstFileA   (KERNEL32.@)
2110  */
2111 HANDLE WINAPI FindFirstFileA( LPCSTR lpFileName, WIN32_FIND_DATAA *lpFindData )
2112 {
2113     return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
2114                             FindExSearchNameMatch, NULL, 0);
2115 }
2116
2117 /*************************************************************************
2118  *           FindFirstFileExA   (KERNEL32.@)
2119  */
2120 HANDLE WINAPI FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId,
2121                                 LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp,
2122                                 LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
2123 {
2124     HANDLE handle;
2125     WIN32_FIND_DATAA *dataA;
2126     WIN32_FIND_DATAW dataW;
2127     WCHAR *nameW;
2128
2129     if (!(nameW = FILE_name_AtoW( lpFileName, FALSE ))) return INVALID_HANDLE_VALUE;
2130
2131     handle = FindFirstFileExW(nameW, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
2132     if (handle == INVALID_HANDLE_VALUE) return handle;
2133
2134     dataA = lpFindFileData;
2135     dataA->dwFileAttributes = dataW.dwFileAttributes;
2136     dataA->ftCreationTime   = dataW.ftCreationTime;
2137     dataA->ftLastAccessTime = dataW.ftLastAccessTime;
2138     dataA->ftLastWriteTime  = dataW.ftLastWriteTime;
2139     dataA->nFileSizeHigh    = dataW.nFileSizeHigh;
2140     dataA->nFileSizeLow     = dataW.nFileSizeLow;
2141     FILE_name_WtoA( dataW.cFileName, -1, dataA->cFileName, sizeof(dataA->cFileName) );
2142     FILE_name_WtoA( dataW.cAlternateFileName, -1, dataA->cAlternateFileName,
2143                     sizeof(dataA->cAlternateFileName) );
2144     return handle;
2145 }
2146
2147
2148 /*************************************************************************
2149  *           FindFirstFileW   (KERNEL32.@)
2150  */
2151 HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
2152 {
2153     return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
2154                             FindExSearchNameMatch, NULL, 0);
2155 }
2156
2157
2158 /*************************************************************************
2159  *           FindNextFileA   (KERNEL32.@)
2160  */
2161 BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
2162 {
2163     WIN32_FIND_DATAW dataW;
2164
2165     if (!FindNextFileW( handle, &dataW )) return FALSE;
2166     data->dwFileAttributes = dataW.dwFileAttributes;
2167     data->ftCreationTime   = dataW.ftCreationTime;
2168     data->ftLastAccessTime = dataW.ftLastAccessTime;
2169     data->ftLastWriteTime  = dataW.ftLastWriteTime;
2170     data->nFileSizeHigh    = dataW.nFileSizeHigh;
2171     data->nFileSizeLow     = dataW.nFileSizeLow;
2172     FILE_name_WtoA( dataW.cFileName, -1, data->cFileName, sizeof(data->cFileName) );
2173     FILE_name_WtoA( dataW.cAlternateFileName, -1, data->cAlternateFileName,
2174                     sizeof(data->cAlternateFileName) );
2175     return TRUE;
2176 }
2177
2178
2179 /**************************************************************************
2180  *           GetFileAttributesW   (KERNEL32.@)
2181  */
2182 DWORD WINAPI GetFileAttributesW( LPCWSTR name )
2183 {
2184     FILE_BASIC_INFORMATION info;
2185     UNICODE_STRING nt_name;
2186     OBJECT_ATTRIBUTES attr;
2187     NTSTATUS status;
2188
2189     TRACE("%s\n", debugstr_w(name));
2190
2191     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
2192     {
2193         SetLastError( ERROR_PATH_NOT_FOUND );
2194         return INVALID_FILE_ATTRIBUTES;
2195     }
2196
2197     attr.Length = sizeof(attr);
2198     attr.RootDirectory = 0;
2199     attr.Attributes = OBJ_CASE_INSENSITIVE;
2200     attr.ObjectName = &nt_name;
2201     attr.SecurityDescriptor = NULL;
2202     attr.SecurityQualityOfService = NULL;
2203
2204     status = NtQueryAttributesFile( &attr, &info );
2205     RtlFreeUnicodeString( &nt_name );
2206
2207     if (status == STATUS_SUCCESS) return info.FileAttributes;
2208
2209     /* NtQueryAttributesFile fails on devices, but GetFileAttributesW succeeds */
2210     if (RtlIsDosDeviceName_U( name )) return FILE_ATTRIBUTE_ARCHIVE;
2211
2212     SetLastError( RtlNtStatusToDosError(status) );
2213     return INVALID_FILE_ATTRIBUTES;
2214 }
2215
2216
2217 /**************************************************************************
2218  *           GetFileAttributesA   (KERNEL32.@)
2219  */
2220 DWORD WINAPI GetFileAttributesA( LPCSTR name )
2221 {
2222     WCHAR *nameW;
2223
2224     if (!(nameW = FILE_name_AtoW( name, FALSE ))) return INVALID_FILE_ATTRIBUTES;
2225     return GetFileAttributesW( nameW );
2226 }
2227
2228
2229 /**************************************************************************
2230  *              SetFileAttributesW      (KERNEL32.@)
2231  */
2232 BOOL WINAPI SetFileAttributesW( LPCWSTR name, DWORD attributes )
2233 {
2234     UNICODE_STRING nt_name;
2235     OBJECT_ATTRIBUTES attr;
2236     IO_STATUS_BLOCK io;
2237     NTSTATUS status;
2238     HANDLE handle;
2239
2240     TRACE("%s %x\n", debugstr_w(name), attributes);
2241
2242     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
2243     {
2244         SetLastError( ERROR_PATH_NOT_FOUND );
2245         return FALSE;
2246     }
2247
2248     attr.Length = sizeof(attr);
2249     attr.RootDirectory = 0;
2250     attr.Attributes = OBJ_CASE_INSENSITIVE;
2251     attr.ObjectName = &nt_name;
2252     attr.SecurityDescriptor = NULL;
2253     attr.SecurityQualityOfService = NULL;
2254
2255     status = NtOpenFile( &handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT );
2256     RtlFreeUnicodeString( &nt_name );
2257
2258     if (status == STATUS_SUCCESS)
2259     {
2260         FILE_BASIC_INFORMATION info;
2261
2262         memset( &info, 0, sizeof(info) );
2263         info.FileAttributes = attributes | FILE_ATTRIBUTE_NORMAL;  /* make sure it's not zero */
2264         status = NtSetInformationFile( handle, &io, &info, sizeof(info), FileBasicInformation );
2265         NtClose( handle );
2266     }
2267
2268     if (status == STATUS_SUCCESS) return TRUE;
2269     SetLastError( RtlNtStatusToDosError(status) );
2270     return FALSE;
2271 }
2272
2273
2274 /**************************************************************************
2275  *              SetFileAttributesA      (KERNEL32.@)
2276  */
2277 BOOL WINAPI SetFileAttributesA( LPCSTR name, DWORD attributes )
2278 {
2279     WCHAR *nameW;
2280
2281     if (!(nameW = FILE_name_AtoW( name, FALSE ))) return FALSE;
2282     return SetFileAttributesW( nameW, attributes );
2283 }
2284
2285
2286 /**************************************************************************
2287  *           GetFileAttributesExW   (KERNEL32.@)
2288  */
2289 BOOL WINAPI GetFileAttributesExW( LPCWSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr )
2290 {
2291     FILE_NETWORK_OPEN_INFORMATION info;
2292     WIN32_FILE_ATTRIBUTE_DATA *data = ptr;
2293     UNICODE_STRING nt_name;
2294     OBJECT_ATTRIBUTES attr;
2295     NTSTATUS status;
2296     
2297     TRACE("%s %d %p\n", debugstr_w(name), level, ptr);
2298
2299     if (level != GetFileExInfoStandard)
2300     {
2301         SetLastError( ERROR_INVALID_PARAMETER );
2302         return FALSE;
2303     }
2304
2305     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
2306     {
2307         SetLastError( ERROR_PATH_NOT_FOUND );
2308         return FALSE;
2309     }
2310
2311     attr.Length = sizeof(attr);
2312     attr.RootDirectory = 0;
2313     attr.Attributes = OBJ_CASE_INSENSITIVE;
2314     attr.ObjectName = &nt_name;
2315     attr.SecurityDescriptor = NULL;
2316     attr.SecurityQualityOfService = NULL;
2317
2318     status = NtQueryFullAttributesFile( &attr, &info );
2319     RtlFreeUnicodeString( &nt_name );
2320
2321     if (status != STATUS_SUCCESS)
2322     {
2323         SetLastError( RtlNtStatusToDosError(status) );
2324         return FALSE;
2325     }
2326
2327     data->dwFileAttributes = info.FileAttributes;
2328     data->ftCreationTime.dwLowDateTime    = info.CreationTime.u.LowPart;
2329     data->ftCreationTime.dwHighDateTime   = info.CreationTime.u.HighPart;
2330     data->ftLastAccessTime.dwLowDateTime  = info.LastAccessTime.u.LowPart;
2331     data->ftLastAccessTime.dwHighDateTime = info.LastAccessTime.u.HighPart;
2332     data->ftLastWriteTime.dwLowDateTime   = info.LastWriteTime.u.LowPart;
2333     data->ftLastWriteTime.dwHighDateTime  = info.LastWriteTime.u.HighPart;
2334     data->nFileSizeLow                    = info.EndOfFile.u.LowPart;
2335     data->nFileSizeHigh                   = info.EndOfFile.u.HighPart;
2336     return TRUE;
2337 }
2338
2339
2340 /**************************************************************************
2341  *           GetFileAttributesExA   (KERNEL32.@)
2342  */
2343 BOOL WINAPI GetFileAttributesExA( LPCSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr )
2344 {
2345     WCHAR *nameW;
2346
2347     if (!(nameW = FILE_name_AtoW( name, FALSE ))) return FALSE;
2348     return GetFileAttributesExW( nameW, level, ptr );
2349 }
2350
2351
2352 /******************************************************************************
2353  *           GetCompressedFileSizeW   (KERNEL32.@)
2354  *
2355  * Get the actual number of bytes used on disk.
2356  *
2357  * RETURNS
2358  *    Success: Low-order doubleword of number of bytes
2359  *    Failure: INVALID_FILE_SIZE
2360  */
2361 DWORD WINAPI GetCompressedFileSizeW(
2362     LPCWSTR name,       /* [in]  Pointer to name of file */
2363     LPDWORD size_high ) /* [out] Receives high-order doubleword of size */
2364 {
2365     UNICODE_STRING nt_name;
2366     OBJECT_ATTRIBUTES attr;
2367     IO_STATUS_BLOCK io;
2368     NTSTATUS status;
2369     HANDLE handle;
2370     DWORD ret = INVALID_FILE_SIZE;
2371
2372     TRACE("%s %p\n", debugstr_w(name), size_high);
2373
2374     if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
2375     {
2376         SetLastError( ERROR_PATH_NOT_FOUND );
2377         return INVALID_FILE_SIZE;
2378     }
2379
2380     attr.Length = sizeof(attr);
2381     attr.RootDirectory = 0;
2382     attr.Attributes = OBJ_CASE_INSENSITIVE;
2383     attr.ObjectName = &nt_name;
2384     attr.SecurityDescriptor = NULL;
2385     attr.SecurityQualityOfService = NULL;
2386
2387     status = NtOpenFile( &handle, 0, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT );
2388     RtlFreeUnicodeString( &nt_name );
2389
2390     if (status == STATUS_SUCCESS)
2391     {
2392         /* we don't support compressed files, simply return the file size */
2393         ret = GetFileSize( handle, size_high );
2394         NtClose( handle );
2395     }
2396     else SetLastError( RtlNtStatusToDosError(status) );
2397
2398     return ret;
2399 }
2400
2401
2402 /******************************************************************************
2403  *           GetCompressedFileSizeA   (KERNEL32.@)
2404  *
2405  * See GetCompressedFileSizeW.
2406  */
2407 DWORD WINAPI GetCompressedFileSizeA( LPCSTR name, LPDWORD size_high )
2408 {
2409     WCHAR *nameW;
2410
2411     if (!(nameW = FILE_name_AtoW( name, FALSE ))) return INVALID_FILE_SIZE;
2412     return GetCompressedFileSizeW( nameW, size_high );
2413 }
2414
2415
2416 /***********************************************************************
2417  *           OpenFile   (KERNEL32.@)
2418  */
2419 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
2420 {
2421     HANDLE handle;
2422     FILETIME filetime;
2423     WORD filedatetime[2];
2424
2425     if (!ofs) return HFILE_ERROR;
2426
2427     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
2428           ((mode & 0x3 )==OF_READ)?"OF_READ":
2429           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
2430           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
2431           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
2432           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
2433           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
2434           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
2435           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
2436           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
2437           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
2438           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
2439           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
2440           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
2441           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
2442           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
2443           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
2444           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
2445         );
2446
2447
2448     ofs->cBytes = sizeof(OFSTRUCT);
2449     ofs->nErrCode = 0;
2450     if (mode & OF_REOPEN) name = ofs->szPathName;
2451
2452     if (!name) return HFILE_ERROR;
2453
2454     TRACE("%s %04x\n", name, mode );
2455
2456     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
2457        Are there any cases where getting the path here is wrong?
2458        Uwe Bonnes 1997 Apr 2 */
2459     if (!GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL )) goto error;
2460
2461     /* OF_PARSE simply fills the structure */
2462
2463     if (mode & OF_PARSE)
2464     {
2465         ofs->fFixedDisk = (GetDriveTypeA( ofs->szPathName ) != DRIVE_REMOVABLE);
2466         TRACE("(%s): OF_PARSE, res = '%s'\n", name, ofs->szPathName );
2467         return 0;
2468     }
2469
2470     /* OF_CREATE is completely different from all other options, so
2471        handle it first */
2472
2473     if (mode & OF_CREATE)
2474     {
2475         if ((handle = create_file_OF( name, mode )) == INVALID_HANDLE_VALUE)
2476             goto error;
2477     }
2478     else
2479     {
2480         /* Now look for the file */
2481
2482         if (!SearchPathA( NULL, name, NULL, sizeof(ofs->szPathName), ofs->szPathName, NULL ))
2483             goto error;
2484
2485         TRACE("found %s\n", debugstr_a(ofs->szPathName) );
2486
2487         if (mode & OF_DELETE)
2488         {
2489             if (!DeleteFileA( ofs->szPathName )) goto error;
2490             TRACE("(%s): OF_DELETE return = OK\n", name);
2491             return TRUE;
2492         }
2493
2494         handle = LongToHandle(_lopen( ofs->szPathName, mode ));
2495         if (handle == INVALID_HANDLE_VALUE) goto error;
2496
2497         GetFileTime( handle, NULL, NULL, &filetime );
2498         FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
2499         if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
2500         {
2501             if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
2502             {
2503                 CloseHandle( handle );
2504                 WARN("(%s): OF_VERIFY failed\n", name );
2505                 /* FIXME: what error here? */
2506                 SetLastError( ERROR_FILE_NOT_FOUND );
2507                 goto error;
2508             }
2509         }
2510         ofs->Reserved1 = filedatetime[0];
2511         ofs->Reserved2 = filedatetime[1];
2512     }
2513     TRACE("(%s): OK, return = %p\n", name, handle );
2514     if (mode & OF_EXIST)  /* Return TRUE instead of a handle */
2515     {
2516         CloseHandle( handle );
2517         return TRUE;
2518     }
2519     return HandleToLong(handle);
2520
2521 error:  /* We get here if there was an error opening the file */
2522     ofs->nErrCode = GetLastError();
2523     WARN("(%s): return = HFILE_ERROR error= %d\n", name,ofs->nErrCode );
2524     return HFILE_ERROR;
2525 }