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