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