Removed the FailReadOnly option, this is now the default behavior.
[wine] / dlls / kernel / file.c
1 /*
2  * File handling functions
3  *
4  * Copyright 1993 John Burton
5  * Copyright 1996 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * TODO:
22  *    Fix the CopyFileEx methods to implement the "extended" functionality.
23  *    Right now, they simply call the CopyFile method.
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <stdarg.h>
30
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33 #include "winerror.h"
34 #include "ntstatus.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winternl.h"
39 #include "wincon.h"
40 #include "wine/winbase16.h"
41 #include "kernel_private.h"
42
43 #include "wine/exception.h"
44 #include "excpt.h"
45 #include "wine/unicode.h"
46 #include "wine/debug.h"
47 #include "async.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(file);
50
51 HANDLE dos_handles[DOS_TABLE_SIZE];
52
53 /* info structure for FindFirstFile handle */
54 typedef struct
55 {
56     HANDLE           handle;      /* handle to directory */
57     CRITICAL_SECTION cs;          /* crit section protecting this structure */
58     UNICODE_STRING   mask;        /* file mask */
59     BOOL             is_root;     /* is directory the root of the drive? */
60     UINT             data_pos;    /* current position in dir data */
61     UINT             data_len;    /* length of dir data */
62     BYTE             data[8192];  /* directory data */
63 } FIND_FIRST_INFO;
64
65
66 static WINE_EXCEPTION_FILTER(page_fault)
67 {
68     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
69         return EXCEPTION_EXECUTE_HANDLER;
70     return EXCEPTION_CONTINUE_SEARCH;
71 }
72
73 /**************************************************************************
74  *                      Operations on file handles                        *
75  **************************************************************************/
76
77 /***********************************************************************
78  *           FILE_InitProcessDosHandles
79  *
80  * Allocates the default DOS handles for a process. Called either by
81  * Win32HandleToDosFileHandle below or by the DOSVM stuff.
82  */
83 static void FILE_InitProcessDosHandles( void )
84 {
85     static BOOL init_done /* = FALSE */;
86     HANDLE cp = GetCurrentProcess();
87
88     if (init_done) return;
89     init_done = TRUE;
90     DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0],
91                     0, TRUE, DUPLICATE_SAME_ACCESS);
92     DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1],
93                     0, TRUE, DUPLICATE_SAME_ACCESS);
94     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2],
95                     0, TRUE, DUPLICATE_SAME_ACCESS);
96     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3],
97                     0, TRUE, DUPLICATE_SAME_ACCESS);
98     DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4],
99                     0, TRUE, DUPLICATE_SAME_ACCESS);
100 }
101
102
103 /***********************************************************************
104  *              GetOverlappedResult     (KERNEL32.@)
105  *
106  * Check the result of an Asynchronous data transfer from a file.
107  *
108  * Parameters
109  *   HANDLE hFile                 [in] handle of file to check on
110  *   LPOVERLAPPED lpOverlapped    [in/out] pointer to overlapped
111  *   LPDWORD lpTransferred        [in/out] number of bytes transferred
112  *   BOOL bWait                   [in] wait for the transfer to complete ?
113  *
114  * RETURNS
115  *   TRUE on success
116  *   FALSE on failure
117  *
118  *  If successful (and relevant) lpTransferred will hold the number of
119  *   bytes transferred during the async operation.
120  *
121  * BUGS
122  *
123  * Currently only works for WaitCommEvent, ReadFile, WriteFile
124  *   with communications ports.
125  *
126  */
127 BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
128                                 LPDWORD lpTransferred, BOOL bWait)
129 {
130     DWORD r;
131
132     TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
133
134     if (lpOverlapped==NULL)
135     {
136         ERR("lpOverlapped was null\n");
137         return FALSE;
138     }
139     if (!lpOverlapped->hEvent)
140     {
141         ERR("lpOverlapped->hEvent was null\n");
142         return FALSE;
143     }
144
145     if ( bWait )
146     {
147         do {
148             TRACE("waiting on %p\n",lpOverlapped);
149             r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
150             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
151         } while (r==STATUS_USER_APC);
152     }
153     else if ( lpOverlapped->Internal == STATUS_PENDING )
154     {
155         /* Wait in order to give APCs a chance to run. */
156         /* This is cheating, so we must set the event again in case of success -
157            it may be a non-manual reset event. */
158         do {
159             TRACE("waiting on %p\n",lpOverlapped);
160             r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
161             TRACE("wait on %p returned %ld\n",lpOverlapped,r);
162         } while (r==STATUS_USER_APC);
163         if ( r == WAIT_OBJECT_0 )
164             NtSetEvent ( lpOverlapped->hEvent, NULL );
165     }
166
167     if(lpTransferred)
168         *lpTransferred = lpOverlapped->InternalHigh;
169
170     switch ( lpOverlapped->Internal )
171     {
172     case STATUS_SUCCESS:
173         return TRUE;
174     case STATUS_PENDING:
175         SetLastError ( ERROR_IO_INCOMPLETE );
176         if ( bWait ) ERR ("PENDING status after waiting!\n");
177         return FALSE;
178     default:
179         SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
180         return FALSE;
181     }
182 }
183
184 /***********************************************************************
185  *             CancelIo                   (KERNEL32.@)
186  */
187 BOOL WINAPI CancelIo(HANDLE handle)
188 {
189     async_private *ovp,*t;
190
191     TRACE("handle = %p\n",handle);
192
193     for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
194     {
195         t = ovp->next;
196         if ( ovp->handle == handle )
197              cancel_async ( ovp );
198     }
199     SleepEx(1,TRUE);
200     return TRUE;
201 }
202
203 /***********************************************************************
204  *           _hread   (KERNEL32.@)
205  */
206 LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count)
207 {
208     return _lread( hFile, buffer, count );
209 }
210
211
212 /***********************************************************************
213  *           _hwrite   (KERNEL32.@)
214  *
215  *      experimentation yields that _lwrite:
216  *              o truncates the file at the current position with
217  *                a 0 len write
218  *              o returns 0 on a 0 length write
219  *              o works with console handles
220  *
221  */
222 LONG WINAPI _hwrite( HFILE handle, LPCSTR buffer, LONG count )
223 {
224     DWORD result;
225
226     TRACE("%d %p %ld\n", handle, buffer, count );
227
228     if (!count)
229     {
230         /* Expand or truncate at current position */
231         if (!SetEndOfFile( (HANDLE)handle )) return HFILE_ERROR;
232         return 0;
233     }
234     if (!WriteFile( (HANDLE)handle, buffer, count, &result, NULL ))
235         return HFILE_ERROR;
236     return result;
237 }
238
239
240 /***********************************************************************
241  *           _lclose   (KERNEL32.@)
242  */
243 HFILE WINAPI _lclose( HFILE hFile )
244 {
245     TRACE("handle %d\n", hFile );
246     return CloseHandle( (HANDLE)hFile ) ? 0 : HFILE_ERROR;
247 }
248
249
250 /***********************************************************************
251  *           _lcreat   (KERNEL32.@)
252  */
253 HFILE WINAPI _lcreat( LPCSTR path, INT attr )
254 {
255     /* Mask off all flags not explicitly allowed by the doc */
256     attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
257     TRACE("%s %02x\n", path, attr );
258     return (HFILE)CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
259                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
260                                CREATE_ALWAYS, attr, 0 );
261 }
262
263
264 /***********************************************************************
265  *           _lopen   (KERNEL32.@)
266  */
267 HFILE WINAPI _lopen( LPCSTR path, INT mode )
268 {
269     DWORD access, sharing;
270
271     TRACE("('%s',%04x)\n", path, mode );
272     FILE_ConvertOFMode( mode, &access, &sharing );
273     return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 );
274 }
275
276
277 /***********************************************************************
278  *           _lread   (KERNEL32.@)
279  */
280 UINT WINAPI _lread( HFILE handle, LPVOID buffer, UINT count )
281 {
282     DWORD result;
283     if (!ReadFile( (HANDLE)handle, buffer, count, &result, NULL ))
284         return HFILE_ERROR;
285     return result;
286 }
287
288
289 /***********************************************************************
290  *           _llseek   (KERNEL32.@)
291  */
292 LONG WINAPI _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
293 {
294     return SetFilePointer( (HANDLE)hFile, lOffset, NULL, nOrigin );
295 }
296
297
298 /***********************************************************************
299  *           _lwrite   (KERNEL32.@)
300  */
301 UINT WINAPI _lwrite( HFILE hFile, LPCSTR buffer, UINT count )
302 {
303     return (UINT)_hwrite( hFile, buffer, (LONG)count );
304 }
305
306
307 /***********************************************************************
308  *           FlushFileBuffers   (KERNEL32.@)
309  */
310 BOOL WINAPI FlushFileBuffers( HANDLE hFile )
311 {
312     NTSTATUS            nts;
313     IO_STATUS_BLOCK     ioblk;
314
315     if (is_console_handle( hFile ))
316     {
317         /* this will fail (as expected) for an output handle */
318         /* FIXME: wait until FlushFileBuffers is moved to dll/kernel */
319         /* return FlushConsoleInputBuffer( hFile ); */
320         return TRUE;
321     }
322     nts = NtFlushBuffersFile( hFile, &ioblk );
323     if (nts != STATUS_SUCCESS)
324     {
325         SetLastError( RtlNtStatusToDosError( nts ) );
326         return FALSE;
327     }
328
329     return TRUE;
330 }
331
332
333 /***********************************************************************
334  *           GetFileSize   (KERNEL32.@)
335  */
336 DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD filesizehigh )
337 {
338     BY_HANDLE_FILE_INFORMATION info;
339     if (!GetFileInformationByHandle( hFile, &info )) return -1;
340     if (filesizehigh) *filesizehigh = info.nFileSizeHigh;
341     return info.nFileSizeLow;
342 }
343
344
345 /***********************************************************************
346  *           GetFileSizeEx   (KERNEL32.@)
347  */
348 BOOL WINAPI GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize )
349 {
350     BY_HANDLE_FILE_INFORMATION info;
351
352     if (!lpFileSize)
353     {
354         SetLastError( ERROR_INVALID_PARAMETER );
355         return FALSE;
356     }
357
358     if (!GetFileInformationByHandle( hFile, &info ))
359     {
360         return FALSE;
361     }
362
363     lpFileSize->u.LowPart = info.nFileSizeLow;
364     lpFileSize->u.HighPart = info.nFileSizeHigh;
365
366     return TRUE;
367 }
368
369
370 /**************************************************************************
371  *           LockFile   (KERNEL32.@)
372  */
373 BOOL WINAPI LockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
374                       DWORD count_low, DWORD count_high )
375 {
376     NTSTATUS            status;
377     LARGE_INTEGER       count, offset;
378
379     TRACE( "%p %lx%08lx %lx%08lx\n", 
380            hFile, offset_high, offset_low, count_high, count_low );
381
382     count.u.LowPart = count_low;
383     count.u.HighPart = count_high;
384     offset.u.LowPart = offset_low;
385     offset.u.HighPart = offset_high;
386
387     status = NtLockFile( hFile, 0, NULL, NULL, 
388                          NULL, &offset, &count, NULL, TRUE, TRUE );
389     
390     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
391     return !status;
392 }
393
394
395 /**************************************************************************
396  * LockFileEx [KERNEL32.@]
397  *
398  * Locks a byte range within an open file for shared or exclusive access.
399  *
400  * RETURNS
401  *   success: TRUE
402  *   failure: FALSE
403  *
404  * NOTES
405  * Per Microsoft docs, the third parameter (reserved) must be set to 0.
406  */
407 BOOL WINAPI LockFileEx( HANDLE hFile, DWORD flags, DWORD reserved,
408                         DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
409 {
410     NTSTATUS status;
411     LARGE_INTEGER count, offset;
412
413     if (reserved)
414     {
415         SetLastError( ERROR_INVALID_PARAMETER );
416         return FALSE;
417     }
418
419     TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
420            hFile, overlapped->OffsetHigh, overlapped->Offset, 
421            count_high, count_low, flags );
422
423     count.u.LowPart = count_low;
424     count.u.HighPart = count_high;
425     offset.u.LowPart = overlapped->Offset;
426     offset.u.HighPart = overlapped->OffsetHigh;
427
428     status = NtLockFile( hFile, overlapped->hEvent, NULL, NULL, 
429                          NULL, &offset, &count, NULL, 
430                          flags & LOCKFILE_FAIL_IMMEDIATELY,
431                          flags & LOCKFILE_EXCLUSIVE_LOCK );
432     
433     if (status) SetLastError( RtlNtStatusToDosError(status) );
434     return !status;
435 }
436
437
438 /**************************************************************************
439  *           UnlockFile   (KERNEL32.@)
440  */
441 BOOL WINAPI UnlockFile( HANDLE hFile, DWORD offset_low, DWORD offset_high,
442                         DWORD count_low, DWORD count_high )
443 {
444     NTSTATUS    status;
445     LARGE_INTEGER count, offset;
446
447     count.u.LowPart = count_low;
448     count.u.HighPart = count_high;
449     offset.u.LowPart = offset_low;
450     offset.u.HighPart = offset_high;
451
452     status = NtUnlockFile( hFile, NULL, &offset, &count, NULL);
453     if (status) SetLastError( RtlNtStatusToDosError(status) );
454     return !status;
455 }
456
457
458 /**************************************************************************
459  *           UnlockFileEx   (KERNEL32.@)
460  */
461 BOOL WINAPI UnlockFileEx( HANDLE hFile, DWORD reserved, DWORD count_low, DWORD count_high,
462                           LPOVERLAPPED overlapped )
463 {
464     if (reserved)
465     {
466         SetLastError( ERROR_INVALID_PARAMETER );
467         return FALSE;
468     }
469     if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n");
470
471     return UnlockFile( hFile, overlapped->Offset, overlapped->OffsetHigh, count_low, count_high );
472 }
473
474
475 /***********************************************************************
476  *           Win32HandleToDosFileHandle   (KERNEL32.21)
477  *
478  * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
479  * longer valid after this function (even on failure).
480  *
481  * Note: this is not exactly right, since on Win95 the Win32 handles
482  *       are on top of DOS handles and we do it the other way
483  *       around. Should be good enough though.
484  */
485 HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle )
486 {
487     int i;
488
489     if (!handle || (handle == INVALID_HANDLE_VALUE))
490         return HFILE_ERROR;
491
492     FILE_InitProcessDosHandles();
493     for (i = 0; i < DOS_TABLE_SIZE; i++)
494         if (!dos_handles[i])
495         {
496             dos_handles[i] = handle;
497             TRACE("Got %d for h32 %p\n", i, handle );
498             return (HFILE)i;
499         }
500     CloseHandle( handle );
501     SetLastError( ERROR_TOO_MANY_OPEN_FILES );
502     return HFILE_ERROR;
503 }
504
505
506 /***********************************************************************
507  *           DosFileHandleToWin32Handle   (KERNEL32.20)
508  *
509  * Return the Win32 handle for a DOS handle.
510  *
511  * Note: this is not exactly right, since on Win95 the Win32 handles
512  *       are on top of DOS handles and we do it the other way
513  *       around. Should be good enough though.
514  */
515 HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle )
516 {
517     HFILE16 hfile = (HFILE16)handle;
518     if (hfile < 5) FILE_InitProcessDosHandles();
519     if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile])
520     {
521         SetLastError( ERROR_INVALID_HANDLE );
522         return INVALID_HANDLE_VALUE;
523     }
524     return dos_handles[hfile];
525 }
526
527
528 /***********************************************************************
529  *           DisposeLZ32Handle   (KERNEL32.22)
530  *
531  * Note: this is not entirely correct, we should only close the
532  *       32-bit handle and not the 16-bit one, but we cannot do
533  *       this because of the way our DOS handles are implemented.
534  *       It shouldn't break anything though.
535  */
536 void WINAPI DisposeLZ32Handle( HANDLE handle )
537 {
538     int i;
539
540     if (!handle || (handle == INVALID_HANDLE_VALUE)) return;
541
542     for (i = 5; i < DOS_TABLE_SIZE; i++)
543         if (dos_handles[i] == handle)
544         {
545             dos_handles[i] = 0;
546             CloseHandle( handle );
547             break;
548         }
549 }
550
551 /**************************************************************************
552  *                      Operations on file names                          *
553  **************************************************************************/
554
555 /**************************************************************************
556  *           ReplaceFileW   (KERNEL32.@)
557  *           ReplaceFile    (KERNEL32.@)
558  */
559 BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
560                          LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
561                          LPVOID lpExclude, LPVOID lpReserved)
562 {
563     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName),debugstr_w(lpReplacementFileName),
564                                           debugstr_w(lpBackupFileName),dwReplaceFlags,lpExclude,lpReserved);
565     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
566     return FALSE;
567 }
568
569
570 /**************************************************************************
571  *           ReplaceFileA (KERNEL32.@)
572  */
573 BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
574                          LPCSTR lpBackupFileName, DWORD dwReplaceFlags,
575                          LPVOID lpExclude, LPVOID lpReserved)
576 {
577     FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName,lpReplacementFileName,
578                                           lpBackupFileName,dwReplaceFlags,lpExclude,lpReserved);
579     SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
580     return FALSE;
581 }
582
583
584 /*************************************************************************
585  *           FindFirstFileExW  (KERNEL32.@)
586  */
587 HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
588                                 LPVOID data, FINDEX_SEARCH_OPS search_op,
589                                 LPVOID filter, DWORD flags)
590 {
591     WCHAR buffer[MAX_PATH];
592     WCHAR *mask, *tmp = buffer;
593     FIND_FIRST_INFO *info = NULL;
594     DWORD size;
595
596     if ((search_op != FindExSearchNameMatch) || (flags != 0))
597     {
598         FIXME("options not implemented 0x%08x 0x%08lx\n", search_op, flags );
599         return INVALID_HANDLE_VALUE;
600     }
601     if (level != FindExInfoStandard)
602     {
603         FIXME("info level %d not implemented\n", level );
604         return INVALID_HANDLE_VALUE;
605     }
606     size = RtlGetFullPathName_U( filename, sizeof(buffer), buffer, &mask );
607     if (!size)
608     {
609         SetLastError( ERROR_PATH_NOT_FOUND );
610         return INVALID_HANDLE_VALUE;
611     }
612     if (size > sizeof(buffer))
613     {
614         tmp = HeapAlloc( GetProcessHeap(), 0, size );
615         if (!tmp)
616         {
617             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
618             return INVALID_HANDLE_VALUE;
619         }
620         size = RtlGetFullPathName_U( filename, size, tmp, &mask );
621     }
622
623     if (!mask || !*mask)
624     {
625         SetLastError( ERROR_FILE_NOT_FOUND );
626         goto error;
627     }
628
629     if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info))))
630     {
631         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
632         goto error;
633     }
634
635     if (!RtlCreateUnicodeString( &info->mask, mask ))
636     {
637         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
638         goto error;
639     }
640     *mask = 0;
641
642     /* check if path is the root of the drive */
643     info->is_root = FALSE;
644     if (tmp[0] && tmp[1] == ':')
645     {
646         WCHAR *p = tmp + 2;
647         while (*p == '\\') p++;
648         info->is_root = (*p == 0);
649     }
650
651     info->handle = CreateFileW( tmp, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
652                                 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
653     if (info->handle == INVALID_HANDLE_VALUE)
654     {
655         RtlFreeUnicodeString( &info->mask );
656         goto error;
657     }
658
659     RtlInitializeCriticalSection( &info->cs );
660     info->data_pos = 0;
661     info->data_len = 0;
662     if (tmp != buffer) HeapFree( GetProcessHeap(), 0, tmp );
663
664     if (!FindNextFileW( (HANDLE)info, data ))
665     {
666         TRACE( "%s not found\n", debugstr_w(filename) );
667         FindClose( (HANDLE)info );
668         SetLastError( ERROR_FILE_NOT_FOUND );
669         return INVALID_HANDLE_VALUE;
670     }
671     return (HANDLE)info;
672
673 error:
674     if (tmp != buffer) HeapFree( GetProcessHeap(), 0, tmp );
675     if (info) HeapFree( GetProcessHeap(), 0, info );
676     return INVALID_HANDLE_VALUE;
677 }
678
679
680 /*************************************************************************
681  *           FindNextFileW   (KERNEL32.@)
682  */
683 BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
684 {
685     FIND_FIRST_INFO *info;
686     FILE_BOTH_DIR_INFORMATION *dir_info;
687     BOOL ret = FALSE;
688
689     if (handle == INVALID_HANDLE_VALUE)
690     {
691         SetLastError( ERROR_INVALID_HANDLE );
692         return ret;
693     }
694     info = (FIND_FIRST_INFO *)handle;
695
696     RtlEnterCriticalSection( &info->cs );
697
698     for (;;)
699     {
700         if (info->data_pos >= info->data_len)  /* need to read some more data */
701         {
702             IO_STATUS_BLOCK io;
703
704             NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
705                                   FileBothDirectoryInformation, FALSE, &info->mask, FALSE );
706             if (io.u.Status)
707             {
708                 SetLastError( RtlNtStatusToDosError( io.u.Status ) );
709                 break;
710             }
711             info->data_len = io.Information;
712             info->data_pos = 0;
713         }
714
715         dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
716
717         if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset;
718         else info->data_pos = info->data_len;
719
720         /* don't return '.' and '..' in the root of the drive */
721         if (info->is_root)
722         {
723             if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue;
724             if (dir_info->FileNameLength == 2 * sizeof(WCHAR) &&
725                 dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue;
726         }
727
728         data->dwFileAttributes = dir_info->FileAttributes;
729         data->ftCreationTime   = *(FILETIME *)&dir_info->CreationTime;
730         data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
731         data->ftLastWriteTime  = *(FILETIME *)&dir_info->LastWriteTime;
732         data->nFileSizeHigh    = dir_info->EndOfFile.QuadPart >> 32;
733         data->nFileSizeLow     = (DWORD)dir_info->EndOfFile.QuadPart;
734         data->dwReserved0      = 0;
735         data->dwReserved1      = 0;
736
737         memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
738         data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
739         memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
740         data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0;
741
742         TRACE("returning %s (%s)\n",
743               debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) );
744
745         ret = TRUE;
746         break;
747     }
748
749     RtlLeaveCriticalSection( &info->cs );
750     return ret;
751 }
752
753
754 /*************************************************************************
755  *           FindClose   (KERNEL32.@)
756  */
757 BOOL WINAPI FindClose( HANDLE handle )
758 {
759     FIND_FIRST_INFO *info = (FIND_FIRST_INFO *)handle;
760
761     if (!handle || handle == INVALID_HANDLE_VALUE) goto error;
762
763     __TRY
764     {
765         RtlEnterCriticalSection( &info->cs );
766         if (info->handle) CloseHandle( info->handle );
767         info->handle = 0;
768         RtlFreeUnicodeString( &info->mask );
769         info->mask.Buffer = NULL;
770         info->data_pos = 0;
771         info->data_len = 0;
772     }
773     __EXCEPT(page_fault)
774     {
775         WARN("Illegal handle %p\n", handle);
776         SetLastError( ERROR_INVALID_HANDLE );
777         return FALSE;
778     }
779     __ENDTRY
780
781     RtlLeaveCriticalSection( &info->cs );
782     RtlDeleteCriticalSection( &info->cs );
783     HeapFree(GetProcessHeap(), 0, info);
784     return TRUE;
785
786  error:
787     SetLastError( ERROR_INVALID_HANDLE );
788     return FALSE;
789 }
790
791
792 /*************************************************************************
793  *           FindFirstFileA   (KERNEL32.@)
794  */
795 HANDLE WINAPI FindFirstFileA( LPCSTR lpFileName, WIN32_FIND_DATAA *lpFindData )
796 {
797     return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
798                             FindExSearchNameMatch, NULL, 0);
799 }
800
801 /*************************************************************************
802  *           FindFirstFileExA   (KERNEL32.@)
803  */
804 HANDLE WINAPI FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId,
805                                 LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp,
806                                 LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
807 {
808     HANDLE handle;
809     WIN32_FIND_DATAA *dataA;
810     WIN32_FIND_DATAW dataW;
811     UNICODE_STRING pathW;
812
813     if (!lpFileName)
814     {
815         SetLastError(ERROR_PATH_NOT_FOUND);
816         return INVALID_HANDLE_VALUE;
817     }
818
819     if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
820     {
821         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
822         return INVALID_HANDLE_VALUE;
823     }
824
825     handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
826     RtlFreeUnicodeString(&pathW);
827     if (handle == INVALID_HANDLE_VALUE) return handle;
828
829     dataA = (WIN32_FIND_DATAA *) lpFindFileData;
830     dataA->dwFileAttributes = dataW.dwFileAttributes;
831     dataA->ftCreationTime   = dataW.ftCreationTime;
832     dataA->ftLastAccessTime = dataW.ftLastAccessTime;
833     dataA->ftLastWriteTime  = dataW.ftLastWriteTime;
834     dataA->nFileSizeHigh    = dataW.nFileSizeHigh;
835     dataA->nFileSizeLow     = dataW.nFileSizeLow;
836     WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
837                          dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
838     WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
839                          dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
840     return handle;
841 }
842
843
844 /*************************************************************************
845  *           FindFirstFileW   (KERNEL32.@)
846  */
847 HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
848 {
849     return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
850                             FindExSearchNameMatch, NULL, 0);
851 }
852
853
854 /*************************************************************************
855  *           FindNextFileA   (KERNEL32.@)
856  */
857 BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
858 {
859     WIN32_FIND_DATAW dataW;
860
861     if (!FindNextFileW( handle, &dataW )) return FALSE;
862     data->dwFileAttributes = dataW.dwFileAttributes;
863     data->ftCreationTime   = dataW.ftCreationTime;
864     data->ftLastAccessTime = dataW.ftLastAccessTime;
865     data->ftLastWriteTime  = dataW.ftLastWriteTime;
866     data->nFileSizeHigh    = dataW.nFileSizeHigh;
867     data->nFileSizeLow     = dataW.nFileSizeLow;
868     WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
869                          data->cFileName, sizeof(data->cFileName), NULL, NULL );
870     WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
871                          data->cAlternateFileName,
872                          sizeof(data->cAlternateFileName), NULL, NULL );
873     return TRUE;
874 }
875
876
877 /***********************************************************************
878  *           OpenFile   (KERNEL32.@)
879  */
880 HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
881 {
882     HANDLE handle;
883     FILETIME filetime;
884     WORD filedatetime[2];
885
886     if (!ofs) return HFILE_ERROR;
887
888     TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name,
889           ((mode & 0x3 )==OF_READ)?"OF_READ":
890           ((mode & 0x3 )==OF_WRITE)?"OF_WRITE":
891           ((mode & 0x3 )==OF_READWRITE)?"OF_READWRITE":"unknown",
892           ((mode & 0x70 )==OF_SHARE_COMPAT)?"OF_SHARE_COMPAT":
893           ((mode & 0x70 )==OF_SHARE_DENY_NONE)?"OF_SHARE_DENY_NONE":
894           ((mode & 0x70 )==OF_SHARE_DENY_READ)?"OF_SHARE_DENY_READ":
895           ((mode & 0x70 )==OF_SHARE_DENY_WRITE)?"OF_SHARE_DENY_WRITE":
896           ((mode & 0x70 )==OF_SHARE_EXCLUSIVE)?"OF_SHARE_EXCLUSIVE":"unknown",
897           ((mode & OF_PARSE )==OF_PARSE)?"OF_PARSE ":"",
898           ((mode & OF_DELETE )==OF_DELETE)?"OF_DELETE ":"",
899           ((mode & OF_VERIFY )==OF_VERIFY)?"OF_VERIFY ":"",
900           ((mode & OF_SEARCH )==OF_SEARCH)?"OF_SEARCH ":"",
901           ((mode & OF_CANCEL )==OF_CANCEL)?"OF_CANCEL ":"",
902           ((mode & OF_CREATE )==OF_CREATE)?"OF_CREATE ":"",
903           ((mode & OF_PROMPT )==OF_PROMPT)?"OF_PROMPT ":"",
904           ((mode & OF_EXIST )==OF_EXIST)?"OF_EXIST ":"",
905           ((mode & OF_REOPEN )==OF_REOPEN)?"OF_REOPEN ":""
906         );
907
908
909     ofs->cBytes = sizeof(OFSTRUCT);
910     ofs->nErrCode = 0;
911     if (mode & OF_REOPEN) name = ofs->szPathName;
912
913     if (!name) return HFILE_ERROR;
914
915     TRACE("%s %04x\n", name, mode );
916
917     /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
918        Are there any cases where getting the path here is wrong?
919        Uwe Bonnes 1997 Apr 2 */
920     if (!GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL )) goto error;
921
922     /* OF_PARSE simply fills the structure */
923
924     if (mode & OF_PARSE)
925     {
926         ofs->fFixedDisk = (GetDriveTypeA( ofs->szPathName ) != DRIVE_REMOVABLE);
927         TRACE("(%s): OF_PARSE, res = '%s'\n", name, ofs->szPathName );
928         return 0;
929     }
930
931     /* OF_CREATE is completely different from all other options, so
932        handle it first */
933
934     if (mode & OF_CREATE)
935     {
936         DWORD access, sharing;
937         FILE_ConvertOFMode( mode, &access, &sharing );
938         if ((handle = CreateFileA( name, GENERIC_READ | GENERIC_WRITE,
939                                    sharing, NULL, CREATE_ALWAYS,
940                                    FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
941             goto error;
942     }
943     else
944     {
945         /* Now look for the file */
946
947         if (!SearchPathA( NULL, name, NULL, sizeof(ofs->szPathName), ofs->szPathName, NULL ))
948             goto error;
949
950         TRACE("found %s\n", debugstr_a(ofs->szPathName) );
951
952         if (mode & OF_DELETE)
953         {
954             if (!DeleteFileA( ofs->szPathName )) goto error;
955             TRACE("(%s): OF_DELETE return = OK\n", name);
956             return TRUE;
957         }
958
959         handle = (HANDLE)_lopen( ofs->szPathName, mode );
960         if (handle == INVALID_HANDLE_VALUE) goto error;
961
962         GetFileTime( handle, NULL, NULL, &filetime );
963         FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
964         if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
965         {
966             if (ofs->Reserved1 != filedatetime[0] || ofs->Reserved2 != filedatetime[1] )
967             {
968                 CloseHandle( handle );
969                 WARN("(%s): OF_VERIFY failed\n", name );
970                 /* FIXME: what error here? */
971                 SetLastError( ERROR_FILE_NOT_FOUND );
972                 goto error;
973             }
974         }
975         ofs->Reserved1 = filedatetime[0];
976         ofs->Reserved2 = filedatetime[1];
977     }
978     TRACE("(%s): OK, return = %p\n", name, handle );
979     if (mode & OF_EXIST)  /* Return TRUE instead of a handle */
980     {
981         CloseHandle( handle );
982         return TRUE;
983     }
984     else return (HFILE)handle;
985
986 error:  /* We get here if there was an error opening the file */
987     ofs->nErrCode = GetLastError();
988     WARN("(%s): return = HFILE_ERROR error= %d\n", name,ofs->nErrCode );
989     return HFILE_ERROR;
990 }