makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / kernelbase / file.c
blob18b86820367855875a1a1b02872d3538d31690cc
1 /*
2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996, 2004 Alexandre Julliard
6 * Copyright 2008 Jeff Zaroyko
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.
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.
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
23 #include <stdarg.h>
24 #include <stdio.h>
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "winerror.h"
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winternl.h"
35 #include "winioctl.h"
36 #include "wincon.h"
37 #include "fileapi.h"
38 #include "ddk/ntddk.h"
39 #include "ddk/ntddser.h"
41 #include "kernelbase.h"
42 #include "wine/exception.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(file);
47 /* info structure for FindFirstFile handle */
48 typedef struct
50 DWORD magic; /* magic number */
51 HANDLE handle; /* handle to directory */
52 CRITICAL_SECTION cs; /* crit section protecting this structure */
53 FINDEX_SEARCH_OPS search_op; /* Flags passed to FindFirst. */
54 FINDEX_INFO_LEVELS level; /* Level passed to FindFirst */
55 UNICODE_STRING path; /* NT path used to open the directory */
56 BOOL is_root; /* is directory the root of the drive? */
57 BOOL wildcard; /* did the mask contain wildcard characters? */
58 UINT data_pos; /* current position in dir data */
59 UINT data_len; /* length of dir data */
60 UINT data_size; /* size of data buffer, or 0 when everything has been read */
61 BYTE data[1]; /* directory data */
62 } FIND_FIRST_INFO;
64 #define FIND_FIRST_MAGIC 0xc0ffee11
66 static const UINT max_entry_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] );
68 const WCHAR windows_dir[] = L"C:\\windows";
69 const WCHAR system_dir[] = L"C:\\windows\\system32";
71 static BOOL oem_file_apis;
74 static void WINAPI read_write_apc( void *apc_user, PIO_STATUS_BLOCK io, ULONG reserved )
76 LPOVERLAPPED_COMPLETION_ROUTINE func = apc_user;
77 func( RtlNtStatusToDosError( io->u.Status ), io->Information, (LPOVERLAPPED)io );
80 static const WCHAR *get_machine_wow64_dir( WORD machine )
82 switch (machine)
84 case IMAGE_FILE_MACHINE_TARGET_HOST: return system_dir;
85 case IMAGE_FILE_MACHINE_I386: return L"C:\\windows\\syswow64";
86 case IMAGE_FILE_MACHINE_ARMNT: return L"C:\\windows\\sysarm32";
87 case IMAGE_FILE_MACHINE_AMD64: return L"C:\\windows\\sysx8664";
88 case IMAGE_FILE_MACHINE_ARM64: return L"C:\\windows\\sysarm64";
89 default: return NULL;
94 /***********************************************************************
95 * Operations on file names
96 ***********************************************************************/
99 /***********************************************************************
100 * contains_path
102 * Check if the file name contains a path; helper for SearchPathW.
103 * A relative path is not considered a path unless it starts with ./ or ../
105 static inline BOOL contains_path( const WCHAR *name )
107 if (RtlDetermineDosPathNameType_U( name ) != RELATIVE_PATH) return TRUE;
108 if (name[0] != '.') return FALSE;
109 if (name[1] == '/' || name[1] == '\\') return TRUE;
110 return (name[1] == '.' && (name[2] == '/' || name[2] == '\\'));
114 /***********************************************************************
115 * append_ext
117 static WCHAR *append_ext( const WCHAR *name, const WCHAR *ext )
119 const WCHAR *p;
120 WCHAR *ret;
121 DWORD len;
123 if (!ext) return NULL;
124 p = wcsrchr( name, '.' );
125 if (p && !wcschr( p, '/' ) && !wcschr( p, '\\' )) return NULL;
127 len = lstrlenW( name ) + lstrlenW( ext );
128 if ((ret = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
130 lstrcpyW( ret, name );
131 lstrcatW( ret, ext );
133 return ret;
137 /***********************************************************************
138 * find_actctx_dllpath
140 * Find the path (if any) of the dll from the activation context.
141 * Returned path doesn't include a name.
143 static NTSTATUS find_actctx_dllpath( const WCHAR *name, WCHAR **path )
145 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
146 ACTCTX_SECTION_KEYED_DATA data;
147 UNICODE_STRING nameW;
148 NTSTATUS status;
149 SIZE_T needed, size = 1024;
150 WCHAR *p;
152 RtlInitUnicodeString( &nameW, name );
153 data.cbSize = sizeof(data);
154 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
155 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
156 &nameW, &data );
157 if (status != STATUS_SUCCESS) return status;
159 for (;;)
161 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
163 status = STATUS_NO_MEMORY;
164 goto done;
166 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
167 AssemblyDetailedInformationInActivationContext,
168 info, size, &needed );
169 if (status == STATUS_SUCCESS) break;
170 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
171 RtlFreeHeap( GetProcessHeap(), 0, info );
172 size = needed;
173 /* restart with larger buffer */
176 if (!info->lpAssemblyManifestPath)
178 status = STATUS_SXS_KEY_NOT_FOUND;
179 goto done;
182 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
184 DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
186 p++;
187 if (!dirlen ||
188 CompareStringOrdinal( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) != CSTR_EQUAL ||
189 wcsicmp( p + dirlen, L".manifest" ))
191 /* manifest name does not match directory name, so it's not a global
192 * windows/winsxs manifest; use the manifest directory name instead */
193 dirlen = p - info->lpAssemblyManifestPath;
194 needed = (dirlen + 1) * sizeof(WCHAR);
195 if (!(*path = p = HeapAlloc( GetProcessHeap(), 0, needed )))
197 status = STATUS_NO_MEMORY;
198 goto done;
200 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
201 *(p + dirlen) = 0;
202 goto done;
206 if (!info->lpAssemblyDirectoryName)
208 status = STATUS_SXS_KEY_NOT_FOUND;
209 goto done;
212 needed = sizeof(L"C:\\windows\\winsxs\\") + info->ulAssemblyDirectoryNameLength + sizeof(WCHAR);
214 if (!(*path = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
216 status = STATUS_NO_MEMORY;
217 goto done;
219 lstrcpyW( p, L"C:\\windows\\winsxs\\" );
220 p += lstrlenW(p);
221 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
222 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
223 *p++ = '\\';
224 *p = 0;
225 done:
226 RtlFreeHeap( GetProcessHeap(), 0, info );
227 RtlReleaseActivationContext( data.hActCtx );
228 return status;
232 /***********************************************************************
233 * copy_filename
235 static DWORD copy_filename( const WCHAR *name, WCHAR *buffer, DWORD len )
237 UINT ret = lstrlenW( name ) + 1;
238 if (buffer && len >= ret)
240 lstrcpyW( buffer, name );
241 ret--;
243 return ret;
247 /***********************************************************************
248 * copy_filename_WtoA
250 * copy a file name back to OEM/Ansi, but only if the buffer is large enough
252 static DWORD copy_filename_WtoA( LPCWSTR nameW, LPSTR buffer, DWORD len )
254 UNICODE_STRING strW;
255 DWORD ret;
257 RtlInitUnicodeString( &strW, nameW );
259 ret = oem_file_apis ? RtlUnicodeStringToOemSize( &strW ) : RtlUnicodeStringToAnsiSize( &strW );
260 if (buffer && ret <= len)
262 ANSI_STRING str;
264 str.Buffer = buffer;
265 str.MaximumLength = min( len, UNICODE_STRING_MAX_CHARS );
266 if (oem_file_apis)
267 RtlUnicodeStringToOemString( &str, &strW, FALSE );
268 else
269 RtlUnicodeStringToAnsiString( &str, &strW, FALSE );
270 ret = str.Length; /* length without terminating 0 */
272 return ret;
276 /***********************************************************************
277 * file_name_AtoW
279 * Convert a file name to Unicode, taking into account the OEM/Ansi API mode.
281 * If alloc is FALSE uses the TEB static buffer, so it can only be used when
282 * there is no possibility for the function to do that twice, taking into
283 * account any called function.
285 WCHAR *file_name_AtoW( LPCSTR name, BOOL alloc )
287 ANSI_STRING str;
288 UNICODE_STRING strW, *pstrW;
289 NTSTATUS status;
291 RtlInitAnsiString( &str, name );
292 pstrW = alloc ? &strW : &NtCurrentTeb()->StaticUnicodeString;
293 if (oem_file_apis)
294 status = RtlOemStringToUnicodeString( pstrW, &str, alloc );
295 else
296 status = RtlAnsiStringToUnicodeString( pstrW, &str, alloc );
297 if (status == STATUS_SUCCESS) return pstrW->Buffer;
299 if (status == STATUS_BUFFER_OVERFLOW)
300 SetLastError( ERROR_FILENAME_EXCED_RANGE );
301 else
302 SetLastError( RtlNtStatusToDosError(status) );
303 return NULL;
307 /***********************************************************************
308 * file_name_WtoA
310 * Convert a file name back to OEM/Ansi. Returns number of bytes copied.
312 DWORD file_name_WtoA( LPCWSTR src, INT srclen, LPSTR dest, INT destlen )
314 DWORD ret;
316 if (srclen < 0) srclen = lstrlenW( src ) + 1;
317 if (!destlen)
319 if (oem_file_apis)
321 UNICODE_STRING strW;
322 strW.Buffer = (WCHAR *)src;
323 strW.Length = srclen * sizeof(WCHAR);
324 ret = RtlUnicodeStringToOemSize( &strW ) - 1;
326 else
327 RtlUnicodeToMultiByteSize( &ret, src, srclen * sizeof(WCHAR) );
329 else
331 if (oem_file_apis)
332 RtlUnicodeToOemN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) );
333 else
334 RtlUnicodeToMultiByteN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) );
336 return ret;
340 /******************************************************************************
341 * AreFileApisANSI (kernelbase.@)
343 BOOL WINAPI DECLSPEC_HOTPATCH AreFileApisANSI(void)
345 return !oem_file_apis;
349 /***********************************************************************
350 * CreateDirectoryA (kernelbase.@)
352 BOOL WINAPI DECLSPEC_HOTPATCH CreateDirectoryA( LPCSTR path, LPSECURITY_ATTRIBUTES sa )
354 WCHAR *pathW;
356 if (!(pathW = file_name_AtoW( path, FALSE ))) return FALSE;
357 return CreateDirectoryW( pathW, sa );
361 /***********************************************************************
362 * CreateDirectoryW (kernelbase.@)
364 BOOL WINAPI DECLSPEC_HOTPATCH CreateDirectoryW( LPCWSTR path, LPSECURITY_ATTRIBUTES sa )
366 OBJECT_ATTRIBUTES attr;
367 UNICODE_STRING nt_name;
368 IO_STATUS_BLOCK io;
369 NTSTATUS status;
370 HANDLE handle;
372 TRACE( "%s\n", debugstr_w(path) );
374 if (!RtlDosPathNameToNtPathName_U( path, &nt_name, NULL, NULL ))
376 SetLastError( ERROR_PATH_NOT_FOUND );
377 return FALSE;
379 attr.Length = sizeof(attr);
380 attr.RootDirectory = 0;
381 attr.Attributes = OBJ_CASE_INSENSITIVE;
382 attr.ObjectName = &nt_name;
383 attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL;
384 attr.SecurityQualityOfService = NULL;
386 status = NtCreateFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, NULL,
387 FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_CREATE,
388 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
389 if (status == STATUS_SUCCESS) NtClose( handle );
391 RtlFreeUnicodeString( &nt_name );
392 return set_ntstatus( status );
396 /***********************************************************************
397 * CreateDirectoryEx (kernelbase.@)
399 BOOL WINAPI DECLSPEC_HOTPATCH CreateDirectoryExW( LPCWSTR template, LPCWSTR path,
400 LPSECURITY_ATTRIBUTES sa )
402 return CreateDirectoryW( path, sa );
406 /*************************************************************************
407 * CreateFile2 (kernelbase.@)
409 HANDLE WINAPI DECLSPEC_HOTPATCH CreateFile2( LPCWSTR name, DWORD access, DWORD sharing, DWORD creation,
410 CREATEFILE2_EXTENDED_PARAMETERS *params )
412 LPSECURITY_ATTRIBUTES sa = params ? params->lpSecurityAttributes : NULL;
413 DWORD attributes = params ? params->dwFileAttributes : 0;
414 HANDLE template = params ? params->hTemplateFile : NULL;
416 FIXME( "(%s %x %x %x %p), partial stub\n", debugstr_w(name), access, sharing, creation, params );
418 return CreateFileW( name, access, sharing, sa, creation, attributes, template );
422 /*************************************************************************
423 * CreateFileA (kernelbase.@)
425 HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileA( LPCSTR name, DWORD access, DWORD sharing,
426 LPSECURITY_ATTRIBUTES sa, DWORD creation,
427 DWORD attributes, HANDLE template)
429 WCHAR *nameW;
431 if ((GetVersion() & 0x80000000) && IsBadStringPtrA( name, -1 )) return INVALID_HANDLE_VALUE;
432 if (!(nameW = file_name_AtoW( name, FALSE ))) return INVALID_HANDLE_VALUE;
433 return CreateFileW( nameW, access, sharing, sa, creation, attributes, template );
436 static UINT get_nt_file_options( DWORD attributes )
438 UINT options = 0;
440 if (attributes & FILE_FLAG_BACKUP_SEMANTICS)
441 options |= FILE_OPEN_FOR_BACKUP_INTENT;
442 else
443 options |= FILE_NON_DIRECTORY_FILE;
444 if (attributes & FILE_FLAG_DELETE_ON_CLOSE)
445 options |= FILE_DELETE_ON_CLOSE;
446 if (attributes & FILE_FLAG_NO_BUFFERING)
447 options |= FILE_NO_INTERMEDIATE_BUFFERING;
448 if (!(attributes & FILE_FLAG_OVERLAPPED))
449 options |= FILE_SYNCHRONOUS_IO_NONALERT;
450 if (attributes & FILE_FLAG_RANDOM_ACCESS)
451 options |= FILE_RANDOM_ACCESS;
452 if (attributes & FILE_FLAG_WRITE_THROUGH)
453 options |= FILE_WRITE_THROUGH;
454 return options;
457 /*************************************************************************
458 * CreateFileW (kernelbase.@)
460 HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
461 LPSECURITY_ATTRIBUTES sa, DWORD creation,
462 DWORD attributes, HANDLE template )
464 NTSTATUS status;
465 OBJECT_ATTRIBUTES attr;
466 UNICODE_STRING nameW;
467 IO_STATUS_BLOCK io;
468 HANDLE ret;
469 DWORD dosdev;
470 const WCHAR *vxd_name = NULL;
471 SECURITY_QUALITY_OF_SERVICE qos;
473 static const UINT nt_disposition[5] =
475 FILE_CREATE, /* CREATE_NEW */
476 FILE_OVERWRITE_IF, /* CREATE_ALWAYS */
477 FILE_OPEN, /* OPEN_EXISTING */
478 FILE_OPEN_IF, /* OPEN_ALWAYS */
479 FILE_OVERWRITE /* TRUNCATE_EXISTING */
483 /* sanity checks */
485 if (!filename || !filename[0])
487 SetLastError( ERROR_PATH_NOT_FOUND );
488 return INVALID_HANDLE_VALUE;
491 TRACE( "%s %s%s%s%s%s%s%s creation %d attributes 0x%x\n", debugstr_w(filename),
492 (access & GENERIC_READ) ? "GENERIC_READ " : "",
493 (access & GENERIC_WRITE) ? "GENERIC_WRITE " : "",
494 (access & GENERIC_EXECUTE) ? "GENERIC_EXECUTE " : "",
495 !access ? "QUERY_ACCESS " : "",
496 (sharing & FILE_SHARE_READ) ? "FILE_SHARE_READ " : "",
497 (sharing & FILE_SHARE_WRITE) ? "FILE_SHARE_WRITE " : "",
498 (sharing & FILE_SHARE_DELETE) ? "FILE_SHARE_DELETE " : "",
499 creation, attributes);
501 /* Open a console for CONIN$ or CONOUT$ */
503 if (!wcsicmp( filename, L"CONIN$" ))
504 return open_console( FALSE, access, sa, creation ? OPEN_EXISTING : 0 );
505 if (!wcsicmp( filename, L"CONOUT$" ))
506 return open_console( TRUE, access, sa, creation ? OPEN_EXISTING : 0 );
508 if (!wcsncmp( filename, L"\\\\.\\", 4 ))
510 if ((filename[4] && filename[5] == ':' && !filename[6]) ||
511 !wcsnicmp( filename + 4, L"PIPE\\", 5 ) ||
512 !wcsnicmp( filename + 4, L"MAILSLOT\\", 9 ))
514 dosdev = 0;
516 else if ((dosdev = RtlIsDosDeviceName_U( filename + 4 )))
518 dosdev += MAKELONG( 0, 4*sizeof(WCHAR) ); /* adjust position to start of filename */
520 else if (GetVersion() & 0x80000000)
522 vxd_name = filename + 4;
523 if (!creation) creation = OPEN_EXISTING;
526 else dosdev = RtlIsDosDeviceName_U( filename );
528 if (dosdev)
530 if (LOWORD(dosdev) == 3 * sizeof(WCHAR) &&
531 !wcsnicmp( filename + HIWORD(dosdev)/sizeof(WCHAR), L"CON", 3 ))
533 switch (access & (GENERIC_READ|GENERIC_WRITE))
535 case GENERIC_READ:
536 return open_console( FALSE, access, sa, OPEN_EXISTING );
537 case GENERIC_WRITE:
538 return open_console( TRUE, access, sa, OPEN_EXISTING );
539 default:
540 SetLastError( ERROR_FILE_NOT_FOUND );
541 return INVALID_HANDLE_VALUE;
546 if (creation < CREATE_NEW || creation > TRUNCATE_EXISTING)
548 SetLastError( ERROR_INVALID_PARAMETER );
549 return INVALID_HANDLE_VALUE;
552 if (!RtlDosPathNameToNtPathName_U( filename, &nameW, NULL, NULL ))
554 SetLastError( ERROR_PATH_NOT_FOUND );
555 return INVALID_HANDLE_VALUE;
558 /* now call NtCreateFile */
560 if (attributes & FILE_FLAG_DELETE_ON_CLOSE)
561 access |= DELETE;
563 attr.Length = sizeof(attr);
564 attr.RootDirectory = 0;
565 attr.Attributes = OBJ_CASE_INSENSITIVE;
566 attr.ObjectName = &nameW;
567 attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL;
568 if (attributes & SECURITY_SQOS_PRESENT)
570 qos.Length = sizeof(qos);
571 qos.ImpersonationLevel = (attributes >> 16) & 0x3;
572 qos.ContextTrackingMode = attributes & SECURITY_CONTEXT_TRACKING ? SECURITY_DYNAMIC_TRACKING : SECURITY_STATIC_TRACKING;
573 qos.EffectiveOnly = (attributes & SECURITY_EFFECTIVE_ONLY) != 0;
574 attr.SecurityQualityOfService = &qos;
576 else
577 attr.SecurityQualityOfService = NULL;
579 if (sa && sa->bInheritHandle) attr.Attributes |= OBJ_INHERIT;
581 status = NtCreateFile( &ret, access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &io,
582 NULL, attributes & FILE_ATTRIBUTE_VALID_FLAGS, sharing,
583 nt_disposition[creation - CREATE_NEW],
584 get_nt_file_options( attributes ), NULL, 0 );
585 if (status)
587 if (vxd_name && vxd_name[0])
589 static HANDLE (*vxd_open)(LPCWSTR,DWORD,SECURITY_ATTRIBUTES*);
590 if (!vxd_open) vxd_open = (void *)GetProcAddress( GetModuleHandleW(L"krnl386.exe16"),
591 "__wine_vxd_open" );
592 if (vxd_open && (ret = vxd_open( vxd_name, access, sa ))) goto done;
595 WARN("Unable to create file %s (status %x)\n", debugstr_w(filename), status);
596 ret = INVALID_HANDLE_VALUE;
598 /* In the case file creation was rejected due to CREATE_NEW flag
599 * was specified and file with that name already exists, correct
600 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
601 * Note: RtlNtStatusToDosError is not the subject to blame here.
603 if (status == STATUS_OBJECT_NAME_COLLISION)
604 SetLastError( ERROR_FILE_EXISTS );
605 else
606 SetLastError( RtlNtStatusToDosError(status) );
608 else
610 if ((creation == CREATE_ALWAYS && io.Information == FILE_OVERWRITTEN) ||
611 (creation == OPEN_ALWAYS && io.Information == FILE_OPENED))
612 SetLastError( ERROR_ALREADY_EXISTS );
613 else
614 SetLastError( 0 );
616 RtlFreeUnicodeString( &nameW );
618 done:
619 if (!ret) ret = INVALID_HANDLE_VALUE;
620 TRACE("returning %p\n", ret);
621 return ret;
625 /***********************************************************************
626 * DeleteFileA (kernelbase.@)
628 BOOL WINAPI DECLSPEC_HOTPATCH DeleteFileA( LPCSTR path )
630 WCHAR *pathW;
632 if (!(pathW = file_name_AtoW( path, FALSE ))) return FALSE;
633 return DeleteFileW( pathW );
637 /***********************************************************************
638 * DeleteFileW (kernelbase.@)
640 BOOL WINAPI DECLSPEC_HOTPATCH DeleteFileW( LPCWSTR path )
642 UNICODE_STRING nameW;
643 OBJECT_ATTRIBUTES attr;
644 NTSTATUS status;
645 HANDLE hFile;
646 IO_STATUS_BLOCK io;
648 TRACE( "%s\n", debugstr_w(path) );
650 if (!RtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ))
652 SetLastError( ERROR_PATH_NOT_FOUND );
653 return FALSE;
656 attr.Length = sizeof(attr);
657 attr.RootDirectory = 0;
658 attr.Attributes = OBJ_CASE_INSENSITIVE;
659 attr.ObjectName = &nameW;
660 attr.SecurityDescriptor = NULL;
661 attr.SecurityQualityOfService = NULL;
663 status = NtCreateFile(&hFile, SYNCHRONIZE | DELETE, &attr, &io, NULL, 0,
664 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
665 FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0);
666 if (status == STATUS_SUCCESS) status = NtClose(hFile);
668 RtlFreeUnicodeString( &nameW );
669 return set_ntstatus( status );
673 /****************************************************************************
674 * FindCloseChangeNotification (kernelbase.@)
676 BOOL WINAPI DECLSPEC_HOTPATCH FindCloseChangeNotification( HANDLE handle )
678 return CloseHandle( handle );
682 /****************************************************************************
683 * FindFirstChangeNotificationA (kernelbase.@)
685 HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstChangeNotificationA( LPCSTR path, BOOL subtree, DWORD filter )
687 WCHAR *pathW;
689 if (!(pathW = file_name_AtoW( path, FALSE ))) return INVALID_HANDLE_VALUE;
690 return FindFirstChangeNotificationW( pathW, subtree, filter );
695 * NtNotifyChangeDirectoryFile may write back to the IO_STATUS_BLOCK
696 * asynchronously. We don't care about the contents, but it can't
697 * be placed on the stack since it will go out of scope when we return.
699 static IO_STATUS_BLOCK dummy_iosb;
701 /****************************************************************************
702 * FindFirstChangeNotificationW (kernelbase.@)
704 HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstChangeNotificationW( LPCWSTR path, BOOL subtree, DWORD filter )
706 UNICODE_STRING nt_name;
707 OBJECT_ATTRIBUTES attr;
708 NTSTATUS status;
709 HANDLE handle = INVALID_HANDLE_VALUE;
711 TRACE( "%s %d %x\n", debugstr_w(path), subtree, filter );
713 if (!RtlDosPathNameToNtPathName_U( path, &nt_name, NULL, NULL ))
715 SetLastError( ERROR_PATH_NOT_FOUND );
716 return handle;
719 attr.Length = sizeof(attr);
720 attr.RootDirectory = 0;
721 attr.Attributes = OBJ_CASE_INSENSITIVE;
722 attr.ObjectName = &nt_name;
723 attr.SecurityDescriptor = NULL;
724 attr.SecurityQualityOfService = NULL;
726 status = NtOpenFile( &handle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &attr, &dummy_iosb,
727 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
728 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
729 RtlFreeUnicodeString( &nt_name );
731 if (!set_ntstatus( status )) return INVALID_HANDLE_VALUE;
733 status = NtNotifyChangeDirectoryFile( handle, NULL, NULL, NULL, &dummy_iosb, NULL, 0, filter, subtree );
734 if (status != STATUS_PENDING)
736 NtClose( handle );
737 SetLastError( RtlNtStatusToDosError(status) );
738 return INVALID_HANDLE_VALUE;
740 return handle;
744 /****************************************************************************
745 * FindNextChangeNotification (kernelbase.@)
747 BOOL WINAPI DECLSPEC_HOTPATCH FindNextChangeNotification( HANDLE handle )
749 NTSTATUS status = NtNotifyChangeDirectoryFile( handle, NULL, NULL, NULL, &dummy_iosb,
750 NULL, 0, FILE_NOTIFY_CHANGE_SIZE, 0 );
751 if (status == STATUS_PENDING) return TRUE;
752 return set_ntstatus( status );
756 /******************************************************************************
757 * FindFirstFileExA (kernelbase.@)
759 HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExA( const char *filename, FINDEX_INFO_LEVELS level,
760 void *data, FINDEX_SEARCH_OPS search_op,
761 void *filter, DWORD flags )
763 HANDLE handle;
764 WIN32_FIND_DATAA *dataA = data;
765 WIN32_FIND_DATAW dataW;
766 WCHAR *nameW;
768 if (!(nameW = file_name_AtoW( filename, FALSE ))) return INVALID_HANDLE_VALUE;
770 handle = FindFirstFileExW( nameW, level, &dataW, search_op, filter, flags );
771 if (handle == INVALID_HANDLE_VALUE) return handle;
773 dataA->dwFileAttributes = dataW.dwFileAttributes;
774 dataA->ftCreationTime = dataW.ftCreationTime;
775 dataA->ftLastAccessTime = dataW.ftLastAccessTime;
776 dataA->ftLastWriteTime = dataW.ftLastWriteTime;
777 dataA->nFileSizeHigh = dataW.nFileSizeHigh;
778 dataA->nFileSizeLow = dataW.nFileSizeLow;
779 file_name_WtoA( dataW.cFileName, -1, dataA->cFileName, sizeof(dataA->cFileName) );
780 file_name_WtoA( dataW.cAlternateFileName, -1, dataA->cAlternateFileName,
781 sizeof(dataA->cAlternateFileName) );
782 return handle;
786 /******************************************************************************
787 * FindFirstFileExW (kernelbase.@)
789 HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
790 LPVOID data, FINDEX_SEARCH_OPS search_op,
791 LPVOID filter, DWORD flags )
793 WCHAR *mask;
794 BOOL has_wildcard = FALSE;
795 FIND_FIRST_INFO *info = NULL;
796 UNICODE_STRING nt_name;
797 OBJECT_ATTRIBUTES attr;
798 IO_STATUS_BLOCK io;
799 NTSTATUS status;
800 DWORD size, device = 0;
802 TRACE( "%s %d %p %d %p %x\n", debugstr_w(filename), level, data, search_op, filter, flags );
804 if (flags & ~FIND_FIRST_EX_LARGE_FETCH)
806 FIXME("flags not implemented 0x%08x\n", flags );
808 if (search_op != FindExSearchNameMatch && search_op != FindExSearchLimitToDirectories)
810 FIXME( "search_op not implemented 0x%08x\n", search_op );
811 SetLastError( ERROR_INVALID_PARAMETER );
812 return INVALID_HANDLE_VALUE;
814 if (level != FindExInfoStandard && level != FindExInfoBasic)
816 FIXME("info level %d not implemented\n", level );
817 SetLastError( ERROR_INVALID_PARAMETER );
818 return INVALID_HANDLE_VALUE;
821 if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, &mask, NULL ))
823 SetLastError( ERROR_PATH_NOT_FOUND );
824 return INVALID_HANDLE_VALUE;
827 if (!mask && (device = RtlIsDosDeviceName_U( filename )))
829 WCHAR *dir = NULL;
831 /* we still need to check that the directory can be opened */
833 if (HIWORD(device))
835 if (!(dir = HeapAlloc( GetProcessHeap(), 0, HIWORD(device) + sizeof(WCHAR) )))
837 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
838 goto error;
840 memcpy( dir, filename, HIWORD(device) );
841 dir[HIWORD(device)/sizeof(WCHAR)] = 0;
843 RtlFreeUnicodeString( &nt_name );
844 if (!RtlDosPathNameToNtPathName_U( dir ? dir : L".", &nt_name, &mask, NULL ))
846 HeapFree( GetProcessHeap(), 0, dir );
847 SetLastError( ERROR_PATH_NOT_FOUND );
848 goto error;
850 HeapFree( GetProcessHeap(), 0, dir );
851 size = 0;
853 else if (!mask || !*mask)
855 SetLastError( ERROR_FILE_NOT_FOUND );
856 goto error;
858 else
860 nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
861 has_wildcard = wcspbrk( mask, L"*?" ) != NULL;
862 size = has_wildcard ? 8192 : max_entry_size;
865 if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size] ))))
867 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
868 goto error;
871 /* check if path is the root of the drive, skipping the \??\ prefix */
872 info->is_root = FALSE;
873 if (nt_name.Length >= 6 * sizeof(WCHAR) && nt_name.Buffer[5] == ':')
875 DWORD pos = 6;
876 while (pos * sizeof(WCHAR) < nt_name.Length && nt_name.Buffer[pos] == '\\') pos++;
877 info->is_root = (pos * sizeof(WCHAR) >= nt_name.Length);
880 attr.Length = sizeof(attr);
881 attr.RootDirectory = 0;
882 attr.Attributes = OBJ_CASE_INSENSITIVE;
883 attr.ObjectName = &nt_name;
884 attr.SecurityDescriptor = NULL;
885 attr.SecurityQualityOfService = NULL;
887 status = NtOpenFile( &info->handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
888 FILE_SHARE_READ | FILE_SHARE_WRITE,
889 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
890 if (status != STATUS_SUCCESS)
892 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
893 SetLastError( ERROR_PATH_NOT_FOUND );
894 else
895 SetLastError( RtlNtStatusToDosError(status) );
896 goto error;
899 RtlInitializeCriticalSection( &info->cs );
900 info->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FIND_FIRST_INFO.cs");
901 info->path = nt_name;
902 info->magic = FIND_FIRST_MAGIC;
903 info->wildcard = has_wildcard;
904 info->data_pos = 0;
905 info->data_len = 0;
906 info->data_size = size;
907 info->search_op = search_op;
908 info->level = level;
910 if (device)
912 WIN32_FIND_DATAW *wfd = data;
914 memset( wfd, 0, sizeof(*wfd) );
915 memcpy( wfd->cFileName, filename + HIWORD(device)/sizeof(WCHAR), LOWORD(device) );
916 wfd->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
917 CloseHandle( info->handle );
918 info->handle = 0;
920 else
922 UNICODE_STRING mask_str;
924 RtlInitUnicodeString( &mask_str, mask );
925 status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
926 FileBothDirectoryInformation, FALSE, &mask_str, TRUE );
927 if (status)
929 FindClose( info );
930 SetLastError( RtlNtStatusToDosError( status ) );
931 return INVALID_HANDLE_VALUE;
934 info->data_len = io.Information;
935 if (!has_wildcard) info->data_size = 0; /* we read everything */
937 if (!FindNextFileW( info, data ))
939 TRACE( "%s not found\n", debugstr_w(filename) );
940 FindClose( info );
941 SetLastError( ERROR_FILE_NOT_FOUND );
942 return INVALID_HANDLE_VALUE;
944 if (!has_wildcard) /* we can't find two files with the same name */
946 CloseHandle( info->handle );
947 info->handle = 0;
950 return info;
952 error:
953 HeapFree( GetProcessHeap(), 0, info );
954 RtlFreeUnicodeString( &nt_name );
955 return INVALID_HANDLE_VALUE;
959 /******************************************************************************
960 * FindFirstFileA (kernelbase.@)
962 HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileA( const char *filename, WIN32_FIND_DATAA *data )
964 return FindFirstFileExA( filename, FindExInfoStandard, data, FindExSearchNameMatch, NULL, 0 );
968 /******************************************************************************
969 * FindFirstFileW (kernelbase.@)
971 HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileW( const WCHAR *filename, WIN32_FIND_DATAW *data )
973 return FindFirstFileExW( filename, FindExInfoStandard, data, FindExSearchNameMatch, NULL, 0 );
977 /******************************************************************************
978 * FindNextFileA (kernelbase.@)
980 BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
982 WIN32_FIND_DATAW dataW;
984 if (!FindNextFileW( handle, &dataW )) return FALSE;
985 data->dwFileAttributes = dataW.dwFileAttributes;
986 data->ftCreationTime = dataW.ftCreationTime;
987 data->ftLastAccessTime = dataW.ftLastAccessTime;
988 data->ftLastWriteTime = dataW.ftLastWriteTime;
989 data->nFileSizeHigh = dataW.nFileSizeHigh;
990 data->nFileSizeLow = dataW.nFileSizeLow;
991 file_name_WtoA( dataW.cFileName, -1, data->cFileName, sizeof(data->cFileName) );
992 file_name_WtoA( dataW.cAlternateFileName, -1, data->cAlternateFileName,
993 sizeof(data->cAlternateFileName) );
994 return TRUE;
998 /******************************************************************************
999 * FindNextFileW (kernelbase.@)
1001 BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
1003 FIND_FIRST_INFO *info = handle;
1004 FILE_BOTH_DIR_INFORMATION *dir_info;
1005 BOOL ret = FALSE;
1006 NTSTATUS status;
1008 TRACE( "%p %p\n", handle, data );
1010 if (!handle || handle == INVALID_HANDLE_VALUE || info->magic != FIND_FIRST_MAGIC)
1012 SetLastError( ERROR_INVALID_HANDLE );
1013 return ret;
1016 RtlEnterCriticalSection( &info->cs );
1018 if (!info->handle) SetLastError( ERROR_NO_MORE_FILES );
1019 else for (;;)
1021 if (info->data_pos >= info->data_len) /* need to read some more data */
1023 IO_STATUS_BLOCK io;
1025 if (info->data_size)
1026 status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
1027 FileBothDirectoryInformation, FALSE, NULL, FALSE );
1028 else
1029 status = STATUS_NO_MORE_FILES;
1031 if (!set_ntstatus( status ))
1033 if (status == STATUS_NO_MORE_FILES)
1035 CloseHandle( info->handle );
1036 info->handle = 0;
1038 break;
1040 info->data_len = io.Information;
1041 info->data_pos = 0;
1044 dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
1046 if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset;
1047 else info->data_pos = info->data_len;
1049 /* don't return '.' and '..' in the root of the drive */
1050 if (info->is_root)
1052 if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue;
1053 if (dir_info->FileNameLength == 2 * sizeof(WCHAR) &&
1054 dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue;
1057 data->dwFileAttributes = dir_info->FileAttributes;
1058 data->ftCreationTime = *(FILETIME *)&dir_info->CreationTime;
1059 data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
1060 data->ftLastWriteTime = *(FILETIME *)&dir_info->LastWriteTime;
1061 data->nFileSizeHigh = dir_info->EndOfFile.QuadPart >> 32;
1062 data->nFileSizeLow = (DWORD)dir_info->EndOfFile.QuadPart;
1063 data->dwReserved0 = 0;
1064 data->dwReserved1 = 0;
1066 memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
1067 data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
1069 if (info->level != FindExInfoBasic)
1071 memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
1072 data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0;
1074 else
1075 data->cAlternateFileName[0] = 0;
1077 TRACE( "returning %s (%s)\n",
1078 debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) );
1080 ret = TRUE;
1081 break;
1084 RtlLeaveCriticalSection( &info->cs );
1085 return ret;
1089 /******************************************************************************
1090 * FindClose (kernelbase.@)
1092 BOOL WINAPI DECLSPEC_HOTPATCH FindClose( HANDLE handle )
1094 FIND_FIRST_INFO *info = handle;
1096 if (!handle || handle == INVALID_HANDLE_VALUE)
1098 SetLastError( ERROR_INVALID_HANDLE );
1099 return FALSE;
1102 __TRY
1104 if (info->magic == FIND_FIRST_MAGIC)
1106 RtlEnterCriticalSection( &info->cs );
1107 if (info->magic == FIND_FIRST_MAGIC) /* in case someone else freed it in the meantime */
1109 info->magic = 0;
1110 if (info->handle) CloseHandle( info->handle );
1111 info->handle = 0;
1112 RtlFreeUnicodeString( &info->path );
1113 info->data_pos = 0;
1114 info->data_len = 0;
1115 RtlLeaveCriticalSection( &info->cs );
1116 info->cs.DebugInfo->Spare[0] = 0;
1117 RtlDeleteCriticalSection( &info->cs );
1118 HeapFree( GetProcessHeap(), 0, info );
1122 __EXCEPT_PAGE_FAULT
1124 WARN( "illegal handle %p\n", handle );
1125 SetLastError( ERROR_INVALID_HANDLE );
1126 return FALSE;
1128 __ENDTRY
1130 return TRUE;
1134 /******************************************************************************
1135 * GetCompressedFileSizeA (kernelbase.@)
1137 DWORD WINAPI DECLSPEC_HOTPATCH GetCompressedFileSizeA( LPCSTR name, LPDWORD size_high )
1139 WCHAR *nameW;
1141 if (!(nameW = file_name_AtoW( name, FALSE ))) return INVALID_FILE_SIZE;
1142 return GetCompressedFileSizeW( nameW, size_high );
1146 /******************************************************************************
1147 * GetCompressedFileSizeW (kernelbase.@)
1149 DWORD WINAPI DECLSPEC_HOTPATCH GetCompressedFileSizeW( LPCWSTR name, LPDWORD size_high )
1151 UNICODE_STRING nt_name;
1152 OBJECT_ATTRIBUTES attr;
1153 IO_STATUS_BLOCK io;
1154 NTSTATUS status;
1155 HANDLE handle;
1156 DWORD ret;
1158 TRACE("%s %p\n", debugstr_w(name), size_high);
1160 if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1162 SetLastError( ERROR_PATH_NOT_FOUND );
1163 return INVALID_FILE_SIZE;
1166 attr.Length = sizeof(attr);
1167 attr.RootDirectory = 0;
1168 attr.Attributes = OBJ_CASE_INSENSITIVE;
1169 attr.ObjectName = &nt_name;
1170 attr.SecurityDescriptor = NULL;
1171 attr.SecurityQualityOfService = NULL;
1173 status = NtOpenFile( &handle, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT );
1174 RtlFreeUnicodeString( &nt_name );
1175 if (!set_ntstatus( status )) return INVALID_FILE_SIZE;
1177 /* we don't support compressed files, simply return the file size */
1178 ret = GetFileSize( handle, size_high );
1179 NtClose( handle );
1180 return ret;
1184 /***********************************************************************
1185 * GetCurrentDirectoryA (kernelbase.@)
1187 UINT WINAPI DECLSPEC_HOTPATCH GetCurrentDirectoryA( UINT buflen, LPSTR buf )
1189 WCHAR bufferW[MAX_PATH];
1190 DWORD ret;
1192 if (buflen && buf && ((ULONG_PTR)buf >> 16) == 0)
1194 /* Win9x catches access violations here, returning zero.
1195 * This behaviour resulted in some people not noticing
1196 * that they got the argument order wrong. So let's be
1197 * nice and fail gracefully if buf is invalid and looks
1198 * more like a buflen. */
1199 SetLastError( ERROR_INVALID_PARAMETER );
1200 return 0;
1203 ret = RtlGetCurrentDirectory_U( sizeof(bufferW), bufferW );
1204 if (!ret) return 0;
1205 if (ret > sizeof(bufferW))
1207 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1208 return 0;
1210 return copy_filename_WtoA( bufferW, buf, buflen );
1214 /***********************************************************************
1215 * GetCurrentDirectoryW (kernelbase.@)
1217 UINT WINAPI DECLSPEC_HOTPATCH GetCurrentDirectoryW( UINT buflen, LPWSTR buf )
1219 return RtlGetCurrentDirectory_U( buflen * sizeof(WCHAR), buf ) / sizeof(WCHAR);
1223 /**************************************************************************
1224 * GetFileAttributesA (kernelbase.@)
1226 DWORD WINAPI DECLSPEC_HOTPATCH GetFileAttributesA( LPCSTR name )
1228 WCHAR *nameW;
1230 if (!(nameW = file_name_AtoW( name, FALSE ))) return INVALID_FILE_ATTRIBUTES;
1231 return GetFileAttributesW( nameW );
1235 /**************************************************************************
1236 * GetFileAttributesW (kernelbase.@)
1238 DWORD WINAPI DECLSPEC_HOTPATCH GetFileAttributesW( LPCWSTR name )
1240 FILE_BASIC_INFORMATION info;
1241 UNICODE_STRING nt_name;
1242 OBJECT_ATTRIBUTES attr;
1243 NTSTATUS status;
1245 TRACE( "%s\n", debugstr_w(name) );
1247 if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1249 SetLastError( ERROR_PATH_NOT_FOUND );
1250 return INVALID_FILE_ATTRIBUTES;
1253 attr.Length = sizeof(attr);
1254 attr.RootDirectory = 0;
1255 attr.Attributes = OBJ_CASE_INSENSITIVE;
1256 attr.ObjectName = &nt_name;
1257 attr.SecurityDescriptor = NULL;
1258 attr.SecurityQualityOfService = NULL;
1260 status = NtQueryAttributesFile( &attr, &info );
1261 RtlFreeUnicodeString( &nt_name );
1263 if (status == STATUS_SUCCESS) return info.FileAttributes;
1265 /* NtQueryAttributesFile fails on devices, but GetFileAttributesW succeeds */
1266 if (RtlIsDosDeviceName_U( name )) return FILE_ATTRIBUTE_ARCHIVE;
1268 SetLastError( RtlNtStatusToDosError(status) );
1269 return INVALID_FILE_ATTRIBUTES;
1273 /**************************************************************************
1274 * GetFileAttributesExA (kernelbase.@)
1276 BOOL WINAPI DECLSPEC_HOTPATCH GetFileAttributesExA( LPCSTR name, GET_FILEEX_INFO_LEVELS level, void *ptr )
1278 WCHAR *nameW;
1280 if (!(nameW = file_name_AtoW( name, FALSE ))) return FALSE;
1281 return GetFileAttributesExW( nameW, level, ptr );
1285 /**************************************************************************
1286 * GetFileAttributesExW (kernelbase.@)
1288 BOOL WINAPI DECLSPEC_HOTPATCH GetFileAttributesExW( LPCWSTR name, GET_FILEEX_INFO_LEVELS level, void *ptr )
1290 FILE_NETWORK_OPEN_INFORMATION info;
1291 WIN32_FILE_ATTRIBUTE_DATA *data = ptr;
1292 UNICODE_STRING nt_name;
1293 OBJECT_ATTRIBUTES attr;
1294 NTSTATUS status;
1296 TRACE("%s %d %p\n", debugstr_w(name), level, ptr);
1298 if (level != GetFileExInfoStandard)
1300 SetLastError( ERROR_INVALID_PARAMETER );
1301 return FALSE;
1304 if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
1306 SetLastError( ERROR_PATH_NOT_FOUND );
1307 return FALSE;
1310 attr.Length = sizeof(attr);
1311 attr.RootDirectory = 0;
1312 attr.Attributes = OBJ_CASE_INSENSITIVE;
1313 attr.ObjectName = &nt_name;
1314 attr.SecurityDescriptor = NULL;
1315 attr.SecurityQualityOfService = NULL;
1317 status = NtQueryFullAttributesFile( &attr, &info );
1318 RtlFreeUnicodeString( &nt_name );
1319 if (!set_ntstatus( status )) return FALSE;
1321 data->dwFileAttributes = info.FileAttributes;
1322 data->ftCreationTime.dwLowDateTime = info.CreationTime.u.LowPart;
1323 data->ftCreationTime.dwHighDateTime = info.CreationTime.u.HighPart;
1324 data->ftLastAccessTime.dwLowDateTime = info.LastAccessTime.u.LowPart;
1325 data->ftLastAccessTime.dwHighDateTime = info.LastAccessTime.u.HighPart;
1326 data->ftLastWriteTime.dwLowDateTime = info.LastWriteTime.u.LowPart;
1327 data->ftLastWriteTime.dwHighDateTime = info.LastWriteTime.u.HighPart;
1328 data->nFileSizeLow = info.EndOfFile.u.LowPart;
1329 data->nFileSizeHigh = info.EndOfFile.u.HighPart;
1330 return TRUE;
1334 /***********************************************************************
1335 * GetFullPathNameA (kernelbase.@)
1337 DWORD WINAPI DECLSPEC_HOTPATCH GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, LPSTR *lastpart )
1339 WCHAR *nameW;
1340 WCHAR bufferW[MAX_PATH], *lastpartW = NULL;
1341 DWORD ret;
1343 if (!(nameW = file_name_AtoW( name, FALSE ))) return 0;
1345 ret = GetFullPathNameW( nameW, MAX_PATH, bufferW, &lastpartW );
1347 if (!ret) return 0;
1348 if (ret > MAX_PATH)
1350 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1351 return 0;
1353 ret = copy_filename_WtoA( bufferW, buffer, len );
1354 if (ret < len && lastpart)
1356 if (lastpartW)
1357 *lastpart = buffer + file_name_WtoA( bufferW, lastpartW - bufferW, NULL, 0 );
1358 else
1359 *lastpart = NULL;
1361 return ret;
1365 /***********************************************************************
1366 * GetFullPathNameW (kernelbase.@)
1368 DWORD WINAPI DECLSPEC_HOTPATCH GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer, LPWSTR *lastpart )
1370 return RtlGetFullPathName_U( name, len * sizeof(WCHAR), buffer, lastpart ) / sizeof(WCHAR);
1374 /***********************************************************************
1375 * GetLongPathNameA (kernelbase.@)
1377 DWORD WINAPI DECLSPEC_HOTPATCH GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen )
1379 WCHAR *shortpathW;
1380 WCHAR longpathW[MAX_PATH];
1381 DWORD ret;
1383 TRACE( "%s\n", debugstr_a( shortpath ));
1385 if (!(shortpathW = file_name_AtoW( shortpath, FALSE ))) return 0;
1387 ret = GetLongPathNameW( shortpathW, longpathW, MAX_PATH );
1389 if (!ret) return 0;
1390 if (ret > MAX_PATH)
1392 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1393 return 0;
1395 return copy_filename_WtoA( longpathW, longpath, longlen );
1399 /***********************************************************************
1400 * GetLongPathNameW (kernelbase.@)
1402 DWORD WINAPI DECLSPEC_HOTPATCH GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen )
1404 WCHAR tmplongpath[1024];
1405 DWORD sp = 0, lp = 0, tmplen;
1406 WIN32_FIND_DATAW wfd;
1407 UNICODE_STRING nameW;
1408 LPCWSTR p;
1409 HANDLE handle;
1411 TRACE("%s,%p,%u\n", debugstr_w(shortpath), longpath, longlen);
1413 if (!shortpath)
1415 SetLastError( ERROR_INVALID_PARAMETER );
1416 return 0;
1418 if (!shortpath[0])
1420 SetLastError( ERROR_PATH_NOT_FOUND );
1421 return 0;
1424 if (shortpath[0] == '\\' && shortpath[1] == '\\')
1426 FIXME( "UNC pathname %s\n", debugstr_w(shortpath) );
1427 tmplen = lstrlenW( shortpath );
1428 if (tmplen < longlen)
1430 if (longpath != shortpath) lstrcpyW( longpath, shortpath );
1431 return tmplen;
1433 return tmplen + 1;
1436 /* check for drive letter */
1437 if (shortpath[0] != '/' && shortpath[1] == ':' )
1439 tmplongpath[0] = shortpath[0];
1440 tmplongpath[1] = ':';
1441 lp = sp = 2;
1444 if (wcspbrk( shortpath + sp, L"*?" ))
1446 SetLastError( ERROR_INVALID_NAME );
1447 return 0;
1450 while (shortpath[sp])
1452 /* check for path delimiters and reproduce them */
1453 if (shortpath[sp] == '\\' || shortpath[sp] == '/')
1455 tmplongpath[lp++] = shortpath[sp++];
1456 tmplongpath[lp] = 0; /* terminate string */
1457 continue;
1460 for (p = shortpath + sp; *p && *p != '/' && *p != '\\'; p++);
1461 tmplen = p - (shortpath + sp);
1462 lstrcpynW( tmplongpath + lp, shortpath + sp, tmplen + 1 );
1464 if (tmplongpath[lp] == '.')
1466 if (tmplen == 1 || (tmplen == 2 && tmplongpath[lp + 1] == '.'))
1468 lp += tmplen;
1469 sp += tmplen;
1470 continue;
1474 /* Check if the file exists */
1475 handle = FindFirstFileW( tmplongpath, &wfd );
1476 if (handle == INVALID_HANDLE_VALUE)
1478 TRACE( "not found %s\n", debugstr_w( tmplongpath ));
1479 SetLastError ( ERROR_FILE_NOT_FOUND );
1480 return 0;
1482 FindClose( handle );
1484 /* Use the existing file name if it's a short name */
1485 RtlInitUnicodeString( &nameW, tmplongpath + lp );
1486 if (RtlIsNameLegalDOS8Dot3( &nameW, NULL, NULL )) lstrcpyW( tmplongpath + lp, wfd.cFileName );
1487 lp += lstrlenW( tmplongpath + lp );
1488 sp += tmplen;
1490 tmplen = lstrlenW( shortpath ) - 1;
1491 if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\\') &&
1492 (tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\\'))
1493 tmplongpath[lp++] = shortpath[tmplen];
1494 tmplongpath[lp] = 0;
1496 tmplen = lstrlenW( tmplongpath ) + 1;
1497 if (tmplen <= longlen)
1499 lstrcpyW( longpath, tmplongpath );
1500 TRACE("returning %s\n", debugstr_w( longpath ));
1501 tmplen--; /* length without 0 */
1503 return tmplen;
1507 /***********************************************************************
1508 * GetShortPathNameW (kernelbase.@)
1510 DWORD WINAPI DECLSPEC_HOTPATCH GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen )
1512 WIN32_FIND_DATAW wfd;
1513 WCHAR *tmpshortpath;
1514 HANDLE handle;
1515 LPCWSTR p;
1516 DWORD sp = 0, lp = 0, tmplen, buf_len;
1518 TRACE( "%s,%p,%u\n", debugstr_w(longpath), shortpath, shortlen );
1520 if (!longpath)
1522 SetLastError( ERROR_INVALID_PARAMETER );
1523 return 0;
1525 if (!longpath[0])
1527 SetLastError( ERROR_BAD_PATHNAME );
1528 return 0;
1531 /* code below only removes characters from string, never adds, so this is
1532 * the largest buffer that tmpshortpath will need to have */
1533 buf_len = lstrlenW(longpath) + 1;
1534 tmpshortpath = HeapAlloc( GetProcessHeap(), 0, buf_len * sizeof(WCHAR) );
1535 if (!tmpshortpath)
1537 SetLastError( ERROR_OUTOFMEMORY );
1538 return 0;
1541 if (longpath[0] == '\\' && longpath[1] == '\\' && longpath[2] == '?' && longpath[3] == '\\')
1543 memcpy( tmpshortpath, longpath, 4 * sizeof(WCHAR) );
1544 sp = lp = 4;
1547 if (wcspbrk( longpath + lp, L"*?" ))
1549 HeapFree( GetProcessHeap(), 0, tmpshortpath );
1550 SetLastError( ERROR_INVALID_NAME );
1551 return 0;
1554 /* check for drive letter */
1555 if (longpath[lp] != '/' && longpath[lp + 1] == ':' )
1557 tmpshortpath[sp] = longpath[lp];
1558 tmpshortpath[sp + 1] = ':';
1559 sp += 2;
1560 lp += 2;
1563 while (longpath[lp])
1565 /* check for path delimiters and reproduce them */
1566 if (longpath[lp] == '\\' || longpath[lp] == '/')
1568 tmpshortpath[sp++] = longpath[lp++];
1569 tmpshortpath[sp] = 0; /* terminate string */
1570 continue;
1573 p = longpath + lp;
1574 for (; *p && *p != '/' && *p != '\\'; p++);
1575 tmplen = p - (longpath + lp);
1576 lstrcpynW( tmpshortpath + sp, longpath + lp, tmplen + 1 );
1578 if (tmpshortpath[sp] == '.')
1580 if (tmplen == 1 || (tmplen == 2 && tmpshortpath[sp + 1] == '.'))
1582 sp += tmplen;
1583 lp += tmplen;
1584 continue;
1588 /* Check if the file exists and use the existing short file name */
1589 handle = FindFirstFileW( tmpshortpath, &wfd );
1590 if (handle == INVALID_HANDLE_VALUE) goto notfound;
1591 FindClose( handle );
1593 /* In rare cases (like "a.abcd") short path may be longer than original path.
1594 * Make sure we have enough space in temp buffer. */
1595 if (wfd.cAlternateFileName[0] && tmplen < lstrlenW(wfd.cAlternateFileName))
1597 WCHAR *new_buf;
1598 buf_len += lstrlenW( wfd.cAlternateFileName ) - tmplen;
1599 new_buf = HeapReAlloc( GetProcessHeap(), 0, tmpshortpath, buf_len * sizeof(WCHAR) );
1600 if(!new_buf)
1602 HeapFree( GetProcessHeap(), 0, tmpshortpath );
1603 SetLastError( ERROR_OUTOFMEMORY );
1604 return 0;
1606 tmpshortpath = new_buf;
1609 lstrcpyW( tmpshortpath + sp, wfd.cAlternateFileName[0] ? wfd.cAlternateFileName : wfd.cFileName );
1610 sp += lstrlenW( tmpshortpath + sp );
1611 lp += tmplen;
1613 tmpshortpath[sp] = 0;
1615 tmplen = lstrlenW( tmpshortpath ) + 1;
1616 if (tmplen <= shortlen)
1618 lstrcpyW( shortpath, tmpshortpath );
1619 TRACE( "returning %s\n", debugstr_w( shortpath ));
1620 tmplen--; /* length without 0 */
1623 HeapFree( GetProcessHeap(), 0, tmpshortpath );
1624 return tmplen;
1626 notfound:
1627 HeapFree( GetProcessHeap(), 0, tmpshortpath );
1628 TRACE( "not found\n" );
1629 SetLastError( ERROR_FILE_NOT_FOUND );
1630 return 0;
1634 /***********************************************************************
1635 * GetSystemDirectoryA (kernelbase.@)
1637 UINT WINAPI DECLSPEC_HOTPATCH GetSystemDirectoryA( LPSTR path, UINT count )
1639 return copy_filename_WtoA( system_dir, path, count );
1643 /***********************************************************************
1644 * GetSystemDirectoryW (kernelbase.@)
1646 UINT WINAPI DECLSPEC_HOTPATCH GetSystemDirectoryW( LPWSTR path, UINT count )
1648 return copy_filename( system_dir, path, count );
1652 /***********************************************************************
1653 * GetSystemWindowsDirectoryA (kernelbase.@)
1655 UINT WINAPI DECLSPEC_HOTPATCH GetSystemWindowsDirectoryA( LPSTR path, UINT count )
1657 return GetWindowsDirectoryA( path, count );
1661 /***********************************************************************
1662 * GetSystemWindowsDirectoryW (kernelbase.@)
1664 UINT WINAPI DECLSPEC_HOTPATCH GetSystemWindowsDirectoryW( LPWSTR path, UINT count )
1666 return GetWindowsDirectoryW( path, count );
1670 /***********************************************************************
1671 * GetSystemWow64DirectoryA (kernelbase.@)
1673 UINT WINAPI /* DECLSPEC_HOTPATCH */ GetSystemWow64DirectoryA( LPSTR path, UINT count )
1675 if (!is_win64 && !is_wow64)
1677 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1678 return 0;
1680 return copy_filename_WtoA( get_machine_wow64_dir( IMAGE_FILE_MACHINE_I386 ), path, count );
1684 /***********************************************************************
1685 * GetSystemWow64DirectoryW (kernelbase.@)
1687 UINT WINAPI /* DECLSPEC_HOTPATCH */ GetSystemWow64DirectoryW( LPWSTR path, UINT count )
1689 if (!is_win64 && !is_wow64)
1691 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1692 return 0;
1694 return copy_filename( get_machine_wow64_dir( IMAGE_FILE_MACHINE_I386 ), path, count );
1698 /***********************************************************************
1699 * GetSystemWow64Directory2A (kernelbase.@)
1701 UINT WINAPI DECLSPEC_HOTPATCH GetSystemWow64Directory2A( LPSTR path, UINT count, WORD machine )
1703 const WCHAR *dir = get_machine_wow64_dir( machine );
1705 return dir ? copy_filename_WtoA( dir, path, count ) : 0;
1709 /***********************************************************************
1710 * GetSystemWow64Directory2W (kernelbase.@)
1712 UINT WINAPI DECLSPEC_HOTPATCH GetSystemWow64Directory2W( LPWSTR path, UINT count, WORD machine )
1714 const WCHAR *dir = get_machine_wow64_dir( machine );
1716 return dir ? copy_filename( dir, path, count ) : 0;
1720 /***********************************************************************
1721 * GetTempFileNameA (kernelbase.@)
1723 UINT WINAPI DECLSPEC_HOTPATCH GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique, LPSTR buffer )
1725 WCHAR *pathW, *prefixW = NULL;
1726 WCHAR bufferW[MAX_PATH];
1727 UINT ret;
1729 if (!(pathW = file_name_AtoW( path, FALSE ))) return 0;
1730 if (prefix && !(prefixW = file_name_AtoW( prefix, TRUE ))) return 0;
1732 ret = GetTempFileNameW( pathW, prefixW, unique, bufferW );
1733 if (ret) file_name_WtoA( bufferW, -1, buffer, MAX_PATH );
1735 HeapFree( GetProcessHeap(), 0, prefixW );
1736 return ret;
1740 /***********************************************************************
1741 * GetTempFileNameW (kernelbase.@)
1743 UINT WINAPI DECLSPEC_HOTPATCH GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, LPWSTR buffer )
1745 int i;
1746 LPWSTR p;
1747 DWORD attr;
1749 if (!path || !buffer)
1751 SetLastError( ERROR_INVALID_PARAMETER );
1752 return 0;
1755 /* ensure that the provided directory exists */
1756 attr = GetFileAttributesW( path );
1757 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
1759 TRACE( "path not found %s\n", debugstr_w( path ));
1760 SetLastError( ERROR_DIRECTORY );
1761 return 0;
1764 lstrcpyW( buffer, path );
1765 p = buffer + lstrlenW(buffer);
1767 /* add a \, if there isn't one */
1768 if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
1770 if (prefix) for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1772 unique &= 0xffff;
1773 if (unique) swprintf( p, MAX_PATH - (p - buffer), L"%x.tmp", unique );
1774 else
1776 /* get a "random" unique number and try to create the file */
1777 HANDLE handle;
1778 UINT num = NtGetTickCount() & 0xffff;
1779 static UINT last;
1781 /* avoid using the same name twice in a short interval */
1782 if (last - num < 10) num = last + 1;
1783 if (!num) num = 1;
1784 unique = num;
1787 swprintf( p, MAX_PATH - (p - buffer), L"%x.tmp", unique );
1788 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1789 if (handle != INVALID_HANDLE_VALUE)
1790 { /* We created it */
1791 CloseHandle( handle );
1792 last = unique;
1793 break;
1795 if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_SHARING_VIOLATION)
1796 break; /* No need to go on */
1797 if (!(++unique & 0xffff)) unique = 1;
1798 } while (unique != num);
1800 TRACE( "returning %s\n", debugstr_w( buffer ));
1801 return unique;
1805 /***********************************************************************
1806 * GetTempPathA (kernelbase.@)
1808 DWORD WINAPI DECLSPEC_HOTPATCH GetTempPathA( DWORD count, LPSTR path )
1810 WCHAR pathW[MAX_PATH];
1811 UINT ret;
1813 if (!(ret = GetTempPathW( MAX_PATH, pathW ))) return 0;
1814 if (ret > MAX_PATH)
1816 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1817 return 0;
1819 return copy_filename_WtoA( pathW, path, count );
1823 /***********************************************************************
1824 * GetTempPathW (kernelbase.@)
1826 DWORD WINAPI DECLSPEC_HOTPATCH GetTempPathW( DWORD count, LPWSTR path )
1828 WCHAR tmp_path[MAX_PATH];
1829 UINT ret;
1831 if (!(ret = GetEnvironmentVariableW( L"TMP", tmp_path, MAX_PATH )) &&
1832 !(ret = GetEnvironmentVariableW( L"TEMP", tmp_path, MAX_PATH )) &&
1833 !(ret = GetEnvironmentVariableW( L"USERPROFILE", tmp_path, MAX_PATH )) &&
1834 !(ret = GetWindowsDirectoryW( tmp_path, MAX_PATH )))
1835 return 0;
1837 if (ret > MAX_PATH)
1839 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1840 return 0;
1842 ret = GetFullPathNameW( tmp_path, MAX_PATH, tmp_path, NULL );
1843 if (!ret) return 0;
1845 if (ret > MAX_PATH - 2)
1847 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1848 return 0;
1850 if (tmp_path[ret-1] != '\\')
1852 tmp_path[ret++] = '\\';
1853 tmp_path[ret] = '\0';
1856 ret++; /* add space for terminating 0 */
1857 if (count >= ret)
1859 lstrcpynW( path, tmp_path, count );
1860 /* the remaining buffer must be zeroed up to 32766 bytes in XP or 32767
1861 * bytes after it, we will assume the > XP behavior for now */
1862 memset( path + ret, 0, (min(count, 32767) - ret) * sizeof(WCHAR) );
1863 ret--; /* return length without 0 */
1865 else if (count)
1867 /* the buffer must be cleared if contents will not fit */
1868 memset( path, 0, count * sizeof(WCHAR) );
1871 TRACE( "returning %u, %s\n", ret, debugstr_w( path ));
1872 return ret;
1876 /***********************************************************************
1877 * GetWindowsDirectoryA (kernelbase.@)
1879 UINT WINAPI DECLSPEC_HOTPATCH GetWindowsDirectoryA( LPSTR path, UINT count )
1881 return copy_filename_WtoA( windows_dir, path, count );
1885 /***********************************************************************
1886 * GetWindowsDirectoryW (kernelbase.@)
1888 UINT WINAPI DECLSPEC_HOTPATCH GetWindowsDirectoryW( LPWSTR path, UINT count )
1890 return copy_filename( windows_dir, path, count );
1894 /***********************************************************************
1895 * NeedCurrentDirectoryForExePathA (kernelbase.@)
1897 BOOL WINAPI DECLSPEC_HOTPATCH NeedCurrentDirectoryForExePathA( LPCSTR name )
1899 WCHAR *nameW;
1901 if (!(nameW = file_name_AtoW( name, FALSE ))) return TRUE;
1902 return NeedCurrentDirectoryForExePathW( nameW );
1906 /***********************************************************************
1907 * NeedCurrentDirectoryForExePathW (kernelbase.@)
1909 BOOL WINAPI DECLSPEC_HOTPATCH NeedCurrentDirectoryForExePathW( LPCWSTR name )
1911 WCHAR env_val;
1913 if (wcschr( name, '\\' )) return TRUE;
1914 /* check the existence of the variable, not value */
1915 return !GetEnvironmentVariableW( L"NoDefaultCurrentDirectoryInExePath", &env_val, 1 );
1919 /***********************************************************************
1920 * SearchPathA (kernelbase.@)
1922 DWORD WINAPI DECLSPEC_HOTPATCH SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext,
1923 DWORD buflen, LPSTR buffer, LPSTR *lastpart )
1925 WCHAR *pathW = NULL, *nameW, *extW = NULL;
1926 WCHAR bufferW[MAX_PATH];
1927 DWORD ret;
1929 if (!name)
1931 SetLastError( ERROR_INVALID_PARAMETER );
1932 return 0;
1935 if (!(nameW = file_name_AtoW( name, FALSE ))) return 0;
1936 if (path && !(pathW = file_name_AtoW( path, TRUE ))) return 0;
1937 if (ext && !(extW = file_name_AtoW( ext, TRUE )))
1939 RtlFreeHeap( GetProcessHeap(), 0, pathW );
1940 return 0;
1943 ret = SearchPathW( pathW, nameW, extW, MAX_PATH, bufferW, NULL );
1945 RtlFreeHeap( GetProcessHeap(), 0, pathW );
1946 RtlFreeHeap( GetProcessHeap(), 0, extW );
1948 if (!ret) return 0;
1949 if (ret > MAX_PATH)
1951 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1952 return 0;
1954 ret = copy_filename_WtoA( bufferW, buffer, buflen );
1955 if (buflen > ret && lastpart) *lastpart = strrchr(buffer, '\\') + 1;
1956 return ret;
1960 /***********************************************************************
1961 * SearchPathW (kernelbase.@)
1963 DWORD WINAPI DECLSPEC_HOTPATCH SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DWORD buflen,
1964 LPWSTR buffer, LPWSTR *lastpart )
1966 DWORD ret = 0;
1967 WCHAR *name_ext;
1969 if (!name || !name[0])
1971 SetLastError( ERROR_INVALID_PARAMETER );
1972 return 0;
1975 /* If the name contains an explicit path, ignore the path */
1977 if (contains_path( name ))
1979 /* try first without extension */
1980 if (RtlDoesFileExists_U( name )) return GetFullPathNameW( name, buflen, buffer, lastpart );
1982 if ((name_ext = append_ext( name, ext )))
1984 if (RtlDoesFileExists_U( name_ext ))
1985 ret = GetFullPathNameW( name_ext, buflen, buffer, lastpart );
1986 RtlFreeHeap( GetProcessHeap(), 0, name_ext );
1989 else if (path && path[0]) /* search in the specified path */
1991 ret = RtlDosSearchPath_U( path, name, ext, buflen * sizeof(WCHAR),
1992 buffer, lastpart ) / sizeof(WCHAR);
1994 else /* search in active context and default path */
1996 WCHAR *dll_path = NULL, *name_ext = append_ext( name, ext );
1998 if (name_ext) name = name_ext;
2000 /* When file is found with activation context no attempt is made
2001 to check if it's really exist, path is returned only basing on context info. */
2002 if (find_actctx_dllpath( name, &dll_path ) == STATUS_SUCCESS)
2004 ret = lstrlenW( dll_path ) + lstrlenW( name ) + 1;
2006 /* count null termination char too */
2007 if (ret <= buflen)
2009 lstrcpyW( buffer, dll_path );
2010 lstrcatW( buffer, name );
2011 if (lastpart) *lastpart = buffer + lstrlenW( dll_path );
2012 ret--;
2014 else if (lastpart) *lastpart = NULL;
2015 RtlFreeHeap( GetProcessHeap(), 0, dll_path );
2017 else if (!RtlGetSearchPath( &dll_path ))
2019 ret = RtlDosSearchPath_U( dll_path, name, NULL, buflen * sizeof(WCHAR),
2020 buffer, lastpart ) / sizeof(WCHAR);
2021 RtlReleasePath( dll_path );
2023 RtlFreeHeap( GetProcessHeap(), 0, name_ext );
2026 if (!ret) SetLastError( ERROR_FILE_NOT_FOUND );
2027 else TRACE( "found %s\n", debugstr_w(buffer) );
2028 return ret;
2032 /***********************************************************************
2033 * SetCurrentDirectoryA (kernelbase.@)
2035 BOOL WINAPI DECLSPEC_HOTPATCH SetCurrentDirectoryA( LPCSTR dir )
2037 WCHAR *dirW;
2038 UNICODE_STRING strW;
2040 if (!(dirW = file_name_AtoW( dir, FALSE ))) return FALSE;
2041 RtlInitUnicodeString( &strW, dirW );
2042 return set_ntstatus( RtlSetCurrentDirectory_U( &strW ));
2046 /***********************************************************************
2047 * SetCurrentDirectoryW (kernelbase.@)
2049 BOOL WINAPI DECLSPEC_HOTPATCH SetCurrentDirectoryW( LPCWSTR dir )
2051 UNICODE_STRING dirW;
2053 RtlInitUnicodeString( &dirW, dir );
2054 return set_ntstatus( RtlSetCurrentDirectory_U( &dirW ));
2058 /**************************************************************************
2059 * SetFileApisToANSI (kernelbase.@)
2061 void WINAPI DECLSPEC_HOTPATCH SetFileApisToANSI(void)
2063 oem_file_apis = FALSE;
2067 /**************************************************************************
2068 * SetFileApisToOEM (kernelbase.@)
2070 void WINAPI DECLSPEC_HOTPATCH SetFileApisToOEM(void)
2072 oem_file_apis = TRUE;
2076 /**************************************************************************
2077 * SetFileAttributesA (kernelbase.@)
2079 BOOL WINAPI DECLSPEC_HOTPATCH SetFileAttributesA( LPCSTR name, DWORD attributes )
2081 WCHAR *nameW;
2083 if (!(nameW = file_name_AtoW( name, FALSE ))) return FALSE;
2084 return SetFileAttributesW( nameW, attributes );
2088 /**************************************************************************
2089 * SetFileAttributesW (kernelbase.@)
2091 BOOL WINAPI DECLSPEC_HOTPATCH SetFileAttributesW( LPCWSTR name, DWORD attributes )
2093 UNICODE_STRING nt_name;
2094 OBJECT_ATTRIBUTES attr;
2095 IO_STATUS_BLOCK io;
2096 NTSTATUS status;
2097 HANDLE handle;
2099 TRACE( "%s %x\n", debugstr_w(name), attributes );
2101 if (!RtlDosPathNameToNtPathName_U( name, &nt_name, NULL, NULL ))
2103 SetLastError( ERROR_PATH_NOT_FOUND );
2104 return FALSE;
2107 attr.Length = sizeof(attr);
2108 attr.RootDirectory = 0;
2109 attr.Attributes = OBJ_CASE_INSENSITIVE;
2110 attr.ObjectName = &nt_name;
2111 attr.SecurityDescriptor = NULL;
2112 attr.SecurityQualityOfService = NULL;
2114 status = NtOpenFile( &handle, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT );
2115 RtlFreeUnicodeString( &nt_name );
2117 if (status == STATUS_SUCCESS)
2119 FILE_BASIC_INFORMATION info;
2121 memset( &info, 0, sizeof(info) );
2122 info.FileAttributes = attributes | FILE_ATTRIBUTE_NORMAL; /* make sure it's not zero */
2123 status = NtSetInformationFile( handle, &io, &info, sizeof(info), FileBasicInformation );
2124 NtClose( handle );
2126 return set_ntstatus( status );
2130 /***********************************************************************
2131 * Wow64DisableWow64FsRedirection (kernelbase.@)
2133 BOOL WINAPI DECLSPEC_HOTPATCH Wow64DisableWow64FsRedirection( PVOID *old_value )
2135 return set_ntstatus( RtlWow64EnableFsRedirectionEx( TRUE, (ULONG *)old_value ));
2139 /***********************************************************************
2140 * Wow64RevertWow64FsRedirection (kernelbase.@)
2142 BOOL WINAPI DECLSPEC_HOTPATCH Wow64RevertWow64FsRedirection( PVOID old_value )
2144 return set_ntstatus( RtlWow64EnableFsRedirection( !old_value ));
2148 /***********************************************************************
2149 * Operations on file handles
2150 ***********************************************************************/
2153 /***********************************************************************
2154 * CancelIo (kernelbase.@)
2156 BOOL WINAPI DECLSPEC_HOTPATCH CancelIo( HANDLE handle )
2158 IO_STATUS_BLOCK io;
2160 NtCancelIoFile( handle, &io );
2161 return set_ntstatus( io.u.Status );
2165 /***********************************************************************
2166 * CancelIoEx (kernelbase.@)
2168 BOOL WINAPI DECLSPEC_HOTPATCH CancelIoEx( HANDLE handle, LPOVERLAPPED overlapped )
2170 IO_STATUS_BLOCK io;
2172 NtCancelIoFileEx( handle, (PIO_STATUS_BLOCK)overlapped, &io );
2173 return set_ntstatus( io.u.Status );
2177 /***********************************************************************
2178 * CancelSynchronousIo (kernelbase.@)
2180 BOOL WINAPI DECLSPEC_HOTPATCH CancelSynchronousIo( HANDLE thread )
2182 FIXME( "(%p): stub\n", thread );
2183 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
2184 return FALSE;
2188 /***********************************************************************
2189 * FlushFileBuffers (kernelbase.@)
2191 BOOL WINAPI DECLSPEC_HOTPATCH FlushFileBuffers( HANDLE file )
2193 IO_STATUS_BLOCK iosb;
2195 return set_ntstatus( NtFlushBuffersFile( file, &iosb ));
2199 /***********************************************************************
2200 * GetFileInformationByHandle (kernelbase.@)
2202 BOOL WINAPI DECLSPEC_HOTPATCH GetFileInformationByHandle( HANDLE file, BY_HANDLE_FILE_INFORMATION *info )
2204 FILE_ALL_INFORMATION all_info;
2205 IO_STATUS_BLOCK io;
2206 NTSTATUS status;
2208 status = NtQueryInformationFile( file, &io, &all_info, sizeof(all_info), FileAllInformation );
2209 if (status == STATUS_BUFFER_OVERFLOW) status = STATUS_SUCCESS;
2210 if (!set_ntstatus( status )) return FALSE;
2212 info->dwFileAttributes = all_info.BasicInformation.FileAttributes;
2213 info->ftCreationTime.dwHighDateTime = all_info.BasicInformation.CreationTime.u.HighPart;
2214 info->ftCreationTime.dwLowDateTime = all_info.BasicInformation.CreationTime.u.LowPart;
2215 info->ftLastAccessTime.dwHighDateTime = all_info.BasicInformation.LastAccessTime.u.HighPart;
2216 info->ftLastAccessTime.dwLowDateTime = all_info.BasicInformation.LastAccessTime.u.LowPart;
2217 info->ftLastWriteTime.dwHighDateTime = all_info.BasicInformation.LastWriteTime.u.HighPart;
2218 info->ftLastWriteTime.dwLowDateTime = all_info.BasicInformation.LastWriteTime.u.LowPart;
2219 info->dwVolumeSerialNumber = 0; /* FIXME */
2220 info->nFileSizeHigh = all_info.StandardInformation.EndOfFile.u.HighPart;
2221 info->nFileSizeLow = all_info.StandardInformation.EndOfFile.u.LowPart;
2222 info->nNumberOfLinks = all_info.StandardInformation.NumberOfLinks;
2223 info->nFileIndexHigh = all_info.InternalInformation.IndexNumber.u.HighPart;
2224 info->nFileIndexLow = all_info.InternalInformation.IndexNumber.u.LowPart;
2225 return TRUE;
2229 /***********************************************************************
2230 * GetFileInformationByHandleEx (kernelbase.@)
2232 BOOL WINAPI DECLSPEC_HOTPATCH GetFileInformationByHandleEx( HANDLE handle, FILE_INFO_BY_HANDLE_CLASS class,
2233 LPVOID info, DWORD size )
2235 NTSTATUS status;
2236 IO_STATUS_BLOCK io;
2238 switch (class)
2240 case FileStreamInfo:
2241 case FileCompressionInfo:
2242 case FileRemoteProtocolInfo:
2243 case FileFullDirectoryInfo:
2244 case FileFullDirectoryRestartInfo:
2245 case FileStorageInfo:
2246 case FileAlignmentInfo:
2247 case FileIdExtdDirectoryInfo:
2248 case FileIdExtdDirectoryRestartInfo:
2249 FIXME( "%p, %u, %p, %u\n", handle, class, info, size );
2250 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
2251 return FALSE;
2253 case FileAttributeTagInfo:
2254 status = NtQueryInformationFile( handle, &io, info, size, FileAttributeTagInformation );
2255 break;
2257 case FileBasicInfo:
2258 status = NtQueryInformationFile( handle, &io, info, size, FileBasicInformation );
2259 break;
2261 case FileStandardInfo:
2262 status = NtQueryInformationFile( handle, &io, info, size, FileStandardInformation );
2263 break;
2265 case FileNameInfo:
2266 status = NtQueryInformationFile( handle, &io, info, size, FileNameInformation );
2267 break;
2269 case FileIdInfo:
2270 status = NtQueryInformationFile( handle, &io, info, size, FileIdInformation );
2271 break;
2273 case FileIdBothDirectoryRestartInfo:
2274 case FileIdBothDirectoryInfo:
2275 status = NtQueryDirectoryFile( handle, NULL, NULL, NULL, &io, info, size,
2276 FileIdBothDirectoryInformation, FALSE, NULL,
2277 (class == FileIdBothDirectoryRestartInfo) );
2278 break;
2280 case FileRenameInfo:
2281 case FileDispositionInfo:
2282 case FileAllocationInfo:
2283 case FileIoPriorityHintInfo:
2284 case FileEndOfFileInfo:
2285 default:
2286 SetLastError( ERROR_INVALID_PARAMETER );
2287 return FALSE;
2289 return set_ntstatus( status );
2293 /***********************************************************************
2294 * GetFileSize (kernelbase.@)
2296 DWORD WINAPI DECLSPEC_HOTPATCH GetFileSize( HANDLE file, LPDWORD size_high )
2298 LARGE_INTEGER size;
2300 if (!GetFileSizeEx( file, &size )) return INVALID_FILE_SIZE;
2301 if (size_high) *size_high = size.u.HighPart;
2302 if (size.u.LowPart == INVALID_FILE_SIZE) SetLastError( 0 );
2303 return size.u.LowPart;
2307 /***********************************************************************
2308 * GetFileSizeEx (kernelbase.@)
2310 BOOL WINAPI DECLSPEC_HOTPATCH GetFileSizeEx( HANDLE file, PLARGE_INTEGER size )
2312 FILE_STANDARD_INFORMATION info;
2313 IO_STATUS_BLOCK io;
2315 if (is_console_handle( file ))
2317 SetLastError( ERROR_INVALID_HANDLE );
2318 return FALSE;
2321 if (!set_ntstatus( NtQueryInformationFile( file, &io, &info, sizeof(info), FileStandardInformation )))
2322 return FALSE;
2324 *size = info.EndOfFile;
2325 return TRUE;
2329 /***********************************************************************
2330 * GetFileTime (kernelbase.@)
2332 BOOL WINAPI DECLSPEC_HOTPATCH GetFileTime( HANDLE file, FILETIME *creation,
2333 FILETIME *access, FILETIME *write )
2335 FILE_BASIC_INFORMATION info;
2336 IO_STATUS_BLOCK io;
2338 if (!set_ntstatus( NtQueryInformationFile( file, &io, &info, sizeof(info), FileBasicInformation )))
2339 return FALSE;
2341 if (creation)
2343 creation->dwHighDateTime = info.CreationTime.u.HighPart;
2344 creation->dwLowDateTime = info.CreationTime.u.LowPart;
2346 if (access)
2348 access->dwHighDateTime = info.LastAccessTime.u.HighPart;
2349 access->dwLowDateTime = info.LastAccessTime.u.LowPart;
2351 if (write)
2353 write->dwHighDateTime = info.LastWriteTime.u.HighPart;
2354 write->dwLowDateTime = info.LastWriteTime.u.LowPart;
2356 return TRUE;
2360 /***********************************************************************
2361 * GetFileType (kernelbase.@)
2363 DWORD WINAPI DECLSPEC_HOTPATCH GetFileType( HANDLE file )
2365 FILE_FS_DEVICE_INFORMATION info;
2366 IO_STATUS_BLOCK io;
2368 if (file == (HANDLE)STD_INPUT_HANDLE ||
2369 file == (HANDLE)STD_OUTPUT_HANDLE ||
2370 file == (HANDLE)STD_ERROR_HANDLE)
2371 file = GetStdHandle( (DWORD_PTR)file );
2373 if (is_console_handle( file )) return FILE_TYPE_CHAR;
2375 if (!set_ntstatus( NtQueryVolumeInformationFile( file, &io, &info, sizeof(info),
2376 FileFsDeviceInformation )))
2377 return FILE_TYPE_UNKNOWN;
2379 switch (info.DeviceType)
2381 case FILE_DEVICE_NULL:
2382 case FILE_DEVICE_SERIAL_PORT:
2383 case FILE_DEVICE_PARALLEL_PORT:
2384 case FILE_DEVICE_TAPE:
2385 case FILE_DEVICE_UNKNOWN:
2386 return FILE_TYPE_CHAR;
2387 case FILE_DEVICE_NAMED_PIPE:
2388 return FILE_TYPE_PIPE;
2389 default:
2390 return FILE_TYPE_DISK;
2395 /***********************************************************************
2396 * GetOverlappedResult (kernelbase.@)
2398 BOOL WINAPI DECLSPEC_HOTPATCH GetOverlappedResult( HANDLE file, LPOVERLAPPED overlapped,
2399 LPDWORD result, BOOL wait )
2401 return GetOverlappedResultEx( file, overlapped, result, wait ? INFINITE : 0, FALSE );
2405 /***********************************************************************
2406 * GetOverlappedResultEx (kernelbase.@)
2408 BOOL WINAPI DECLSPEC_HOTPATCH GetOverlappedResultEx( HANDLE file, OVERLAPPED *overlapped,
2409 DWORD *result, DWORD timeout, BOOL alertable )
2411 NTSTATUS status;
2412 DWORD ret;
2414 TRACE( "(%p %p %p %u %d)\n", file, overlapped, result, timeout, alertable );
2416 status = overlapped->Internal;
2417 if (status == STATUS_PENDING)
2419 if (!timeout)
2421 SetLastError( ERROR_IO_INCOMPLETE );
2422 return FALSE;
2424 ret = WaitForSingleObjectEx( overlapped->hEvent ? overlapped->hEvent : file, timeout, alertable );
2425 if (ret == WAIT_FAILED)
2426 return FALSE;
2427 else if (ret)
2429 SetLastError( ret );
2430 return FALSE;
2433 status = overlapped->Internal;
2434 if (status == STATUS_PENDING) status = STATUS_SUCCESS;
2437 *result = overlapped->InternalHigh;
2438 return set_ntstatus( status );
2442 /**************************************************************************
2443 * LockFile (kernelbase.@)
2445 BOOL WINAPI DECLSPEC_HOTPATCH LockFile( HANDLE file, DWORD offset_low, DWORD offset_high,
2446 DWORD count_low, DWORD count_high )
2448 LARGE_INTEGER count, offset;
2450 TRACE( "%p %x%08x %x%08x\n", file, offset_high, offset_low, count_high, count_low );
2452 count.u.LowPart = count_low;
2453 count.u.HighPart = count_high;
2454 offset.u.LowPart = offset_low;
2455 offset.u.HighPart = offset_high;
2456 return set_ntstatus( NtLockFile( file, 0, NULL, NULL, NULL, &offset, &count, NULL, TRUE, TRUE ));
2460 /**************************************************************************
2461 * LockFileEx (kernelbase.@)
2463 BOOL WINAPI DECLSPEC_HOTPATCH LockFileEx( HANDLE file, DWORD flags, DWORD reserved,
2464 DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
2466 LARGE_INTEGER count, offset;
2467 LPVOID cvalue = NULL;
2469 if (reserved)
2471 SetLastError( ERROR_INVALID_PARAMETER );
2472 return FALSE;
2475 TRACE( "%p %x%08x %x%08x flags %x\n",
2476 file, overlapped->u.s.OffsetHigh, overlapped->u.s.Offset, count_high, count_low, flags );
2478 count.u.LowPart = count_low;
2479 count.u.HighPart = count_high;
2480 offset.u.LowPart = overlapped->u.s.Offset;
2481 offset.u.HighPart = overlapped->u.s.OffsetHigh;
2483 if (((ULONG_PTR)overlapped->hEvent & 1) == 0) cvalue = overlapped;
2485 return set_ntstatus( NtLockFile( file, overlapped->hEvent, NULL, cvalue,
2486 NULL, &offset, &count, NULL,
2487 flags & LOCKFILE_FAIL_IMMEDIATELY,
2488 flags & LOCKFILE_EXCLUSIVE_LOCK ));
2492 /***********************************************************************
2493 * OpenFileById (kernelbase.@)
2495 HANDLE WINAPI DECLSPEC_HOTPATCH OpenFileById( HANDLE handle, LPFILE_ID_DESCRIPTOR id, DWORD access,
2496 DWORD share, LPSECURITY_ATTRIBUTES sec_attr, DWORD flags )
2498 UINT options;
2499 HANDLE result;
2500 OBJECT_ATTRIBUTES attr;
2501 IO_STATUS_BLOCK io;
2502 UNICODE_STRING objectName;
2504 if (!id)
2506 SetLastError( ERROR_INVALID_PARAMETER );
2507 return INVALID_HANDLE_VALUE;
2510 options = FILE_OPEN_BY_FILE_ID;
2511 if (flags & FILE_FLAG_BACKUP_SEMANTICS)
2512 options |= FILE_OPEN_FOR_BACKUP_INTENT;
2513 else
2514 options |= FILE_NON_DIRECTORY_FILE;
2515 if (flags & FILE_FLAG_NO_BUFFERING) options |= FILE_NO_INTERMEDIATE_BUFFERING;
2516 if (!(flags & FILE_FLAG_OVERLAPPED)) options |= FILE_SYNCHRONOUS_IO_NONALERT;
2517 if (flags & FILE_FLAG_RANDOM_ACCESS) options |= FILE_RANDOM_ACCESS;
2518 flags &= FILE_ATTRIBUTE_VALID_FLAGS;
2520 objectName.Length = sizeof(ULONGLONG);
2521 objectName.Buffer = (WCHAR *)&id->u.FileId;
2522 attr.Length = sizeof(attr);
2523 attr.RootDirectory = handle;
2524 attr.Attributes = 0;
2525 attr.ObjectName = &objectName;
2526 attr.SecurityDescriptor = sec_attr ? sec_attr->lpSecurityDescriptor : NULL;
2527 attr.SecurityQualityOfService = NULL;
2528 if (sec_attr && sec_attr->bInheritHandle) attr.Attributes |= OBJ_INHERIT;
2530 if (!set_ntstatus( NtCreateFile( &result, access | SYNCHRONIZE, &attr, &io, NULL, flags,
2531 share, OPEN_EXISTING, options, NULL, 0 )))
2532 return INVALID_HANDLE_VALUE;
2533 return result;
2537 /***********************************************************************
2538 * ReOpenFile (kernelbase.@)
2540 HANDLE WINAPI DECLSPEC_HOTPATCH ReOpenFile( HANDLE handle, DWORD access, DWORD sharing, DWORD attributes )
2542 SECURITY_QUALITY_OF_SERVICE qos;
2543 OBJECT_ATTRIBUTES attr;
2544 UNICODE_STRING empty = { 0 };
2545 IO_STATUS_BLOCK io;
2546 NTSTATUS status;
2547 HANDLE file;
2549 TRACE("handle %p, access %#x, sharing %#x, attributes %#x.\n", handle, access, sharing, attributes);
2551 if (attributes & 0x7ffff) /* FILE_ATTRIBUTE_* flags are invalid */
2553 SetLastError(ERROR_INVALID_PARAMETER);
2554 return INVALID_HANDLE_VALUE;
2557 if (attributes & FILE_FLAG_DELETE_ON_CLOSE)
2558 access |= DELETE;
2560 InitializeObjectAttributes( &attr, &empty, OBJ_CASE_INSENSITIVE, handle, NULL );
2561 if (attributes & SECURITY_SQOS_PRESENT)
2563 qos.Length = sizeof(qos);
2564 qos.ImpersonationLevel = (attributes >> 16) & 0x3;
2565 qos.ContextTrackingMode = attributes & SECURITY_CONTEXT_TRACKING ? SECURITY_DYNAMIC_TRACKING : SECURITY_STATIC_TRACKING;
2566 qos.EffectiveOnly = (attributes & SECURITY_EFFECTIVE_ONLY) != 0;
2567 attr.SecurityQualityOfService = &qos;
2570 status = NtCreateFile( &file, access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &io, NULL,
2571 0, sharing, FILE_OPEN, get_nt_file_options( attributes ), NULL, 0 );
2572 if (!set_ntstatus( status ))
2573 return INVALID_HANDLE_VALUE;
2574 return file;
2578 static void WINAPI invoke_completion( void *context, IO_STATUS_BLOCK *io, ULONG res )
2580 LPOVERLAPPED_COMPLETION_ROUTINE completion = context;
2581 completion( io->u.Status, io->Information, (LPOVERLAPPED)io );
2584 /****************************************************************************
2585 * ReadDirectoryChangesW (kernelbase.@)
2587 BOOL WINAPI DECLSPEC_HOTPATCH ReadDirectoryChangesW( HANDLE handle, LPVOID buffer, DWORD len,
2588 BOOL subtree, DWORD filter, LPDWORD returned,
2589 LPOVERLAPPED overlapped,
2590 LPOVERLAPPED_COMPLETION_ROUTINE completion )
2592 OVERLAPPED ov, *pov;
2593 IO_STATUS_BLOCK *ios;
2594 NTSTATUS status;
2595 LPVOID cvalue = NULL;
2597 TRACE( "%p %p %08x %d %08x %p %p %p\n",
2598 handle, buffer, len, subtree, filter, returned, overlapped, completion );
2600 if (!overlapped)
2602 memset( &ov, 0, sizeof ov );
2603 ov.hEvent = CreateEventW( NULL, 0, 0, NULL );
2604 pov = &ov;
2606 else
2608 pov = overlapped;
2609 if (completion) cvalue = completion;
2610 else if (((ULONG_PTR)overlapped->hEvent & 1) == 0) cvalue = overlapped;
2613 ios = (PIO_STATUS_BLOCK)pov;
2614 ios->u.Status = STATUS_PENDING;
2616 status = NtNotifyChangeDirectoryFile( handle, completion && overlapped ? NULL : pov->hEvent,
2617 completion && overlapped ? invoke_completion : NULL,
2618 cvalue, ios, buffer, len, filter, subtree );
2619 if (status == STATUS_PENDING)
2621 if (overlapped) return TRUE;
2622 WaitForSingleObjectEx( ov.hEvent, INFINITE, TRUE );
2623 if (returned) *returned = ios->Information;
2624 status = ios->u.Status;
2626 if (!overlapped) CloseHandle( ov.hEvent );
2627 return set_ntstatus( status );
2631 /***********************************************************************
2632 * ReadFile (kernelbase.@)
2634 BOOL WINAPI DECLSPEC_HOTPATCH ReadFile( HANDLE file, LPVOID buffer, DWORD count,
2635 LPDWORD result, LPOVERLAPPED overlapped )
2637 LARGE_INTEGER offset;
2638 PLARGE_INTEGER poffset = NULL;
2639 IO_STATUS_BLOCK iosb;
2640 PIO_STATUS_BLOCK io_status = &iosb;
2641 HANDLE event = 0;
2642 NTSTATUS status;
2643 LPVOID cvalue = NULL;
2645 TRACE( "%p %p %d %p %p\n", file, buffer, count, result, overlapped );
2647 if (result) *result = 0;
2649 if (overlapped)
2651 offset.u.LowPart = overlapped->u.s.Offset;
2652 offset.u.HighPart = overlapped->u.s.OffsetHigh;
2653 poffset = &offset;
2654 event = overlapped->hEvent;
2655 io_status = (PIO_STATUS_BLOCK)overlapped;
2656 if (((ULONG_PTR)event & 1) == 0) cvalue = overlapped;
2658 else io_status->Information = 0;
2659 io_status->u.Status = STATUS_PENDING;
2661 status = NtReadFile( file, event, NULL, cvalue, io_status, buffer, count, poffset, NULL);
2663 if (status == STATUS_PENDING && !overlapped)
2665 WaitForSingleObject( file, INFINITE );
2666 status = io_status->u.Status;
2669 if (result) *result = overlapped && status ? 0 : io_status->Information;
2671 if (status == STATUS_END_OF_FILE)
2673 if (overlapped != NULL)
2675 SetLastError( RtlNtStatusToDosError(status) );
2676 return FALSE;
2679 else if (status && status != STATUS_TIMEOUT)
2681 SetLastError( RtlNtStatusToDosError(status) );
2682 return FALSE;
2684 return TRUE;
2688 /***********************************************************************
2689 * ReadFileEx (kernelbase.@)
2691 BOOL WINAPI DECLSPEC_HOTPATCH ReadFileEx( HANDLE file, LPVOID buffer, DWORD count, LPOVERLAPPED overlapped,
2692 LPOVERLAPPED_COMPLETION_ROUTINE completion )
2694 PIO_STATUS_BLOCK io;
2695 LARGE_INTEGER offset;
2696 NTSTATUS status;
2698 TRACE( "(file=%p, buffer=%p, bytes=%u, ovl=%p, ovl_fn=%p)\n",
2699 file, buffer, count, overlapped, completion );
2701 if (!overlapped)
2703 SetLastError( ERROR_INVALID_PARAMETER );
2704 return FALSE;
2706 offset.u.LowPart = overlapped->u.s.Offset;
2707 offset.u.HighPart = overlapped->u.s.OffsetHigh;
2708 io = (PIO_STATUS_BLOCK)overlapped;
2709 io->u.Status = STATUS_PENDING;
2710 io->Information = 0;
2712 status = NtReadFile( file, NULL, read_write_apc, completion, io, buffer, count, &offset, NULL);
2713 if (status == STATUS_PENDING) return TRUE;
2714 return set_ntstatus( status );
2718 /***********************************************************************
2719 * ReadFileScatter (kernelbase.@)
2721 BOOL WINAPI DECLSPEC_HOTPATCH ReadFileScatter( HANDLE file, FILE_SEGMENT_ELEMENT *segments, DWORD count,
2722 LPDWORD reserved, LPOVERLAPPED overlapped )
2724 PIO_STATUS_BLOCK io;
2725 LARGE_INTEGER offset;
2726 void *cvalue = NULL;
2728 TRACE( "(%p %p %u %p)\n", file, segments, count, overlapped );
2730 offset.u.LowPart = overlapped->u.s.Offset;
2731 offset.u.HighPart = overlapped->u.s.OffsetHigh;
2732 if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped;
2733 io = (PIO_STATUS_BLOCK)overlapped;
2734 io->u.Status = STATUS_PENDING;
2735 io->Information = 0;
2737 return set_ntstatus( NtReadFileScatter( file, overlapped->hEvent, NULL, cvalue, io,
2738 segments, count, &offset, NULL ));
2742 /**************************************************************************
2743 * SetEndOfFile (kernelbase.@)
2745 BOOL WINAPI DECLSPEC_HOTPATCH SetEndOfFile( HANDLE file )
2747 FILE_POSITION_INFORMATION pos;
2748 FILE_END_OF_FILE_INFORMATION eof;
2749 IO_STATUS_BLOCK io;
2750 NTSTATUS status;
2752 if (!(status = NtQueryInformationFile( file, &io, &pos, sizeof(pos), FilePositionInformation )))
2754 eof.EndOfFile = pos.CurrentByteOffset;
2755 status = NtSetInformationFile( file, &io, &eof, sizeof(eof), FileEndOfFileInformation );
2757 return set_ntstatus( status );
2761 /***********************************************************************
2762 * SetFileInformationByHandle (kernelbase.@)
2764 BOOL WINAPI DECLSPEC_HOTPATCH SetFileInformationByHandle( HANDLE file, FILE_INFO_BY_HANDLE_CLASS class,
2765 void *info, DWORD size )
2767 NTSTATUS status;
2768 IO_STATUS_BLOCK io;
2770 TRACE( "%p %u %p %u\n", file, class, info, size );
2772 switch (class)
2774 case FileNameInfo:
2775 case FileRenameInfo:
2776 case FileAllocationInfo:
2777 case FileEndOfFileInfo:
2778 case FileStreamInfo:
2779 case FileIdBothDirectoryInfo:
2780 case FileIdBothDirectoryRestartInfo:
2781 case FileFullDirectoryInfo:
2782 case FileFullDirectoryRestartInfo:
2783 case FileStorageInfo:
2784 case FileAlignmentInfo:
2785 case FileIdInfo:
2786 case FileIdExtdDirectoryInfo:
2787 case FileIdExtdDirectoryRestartInfo:
2788 FIXME( "%p, %u, %p, %u\n", file, class, info, size );
2789 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
2790 return FALSE;
2792 case FileBasicInfo:
2793 status = NtSetInformationFile( file, &io, info, size, FileBasicInformation );
2794 break;
2795 case FileDispositionInfo:
2796 status = NtSetInformationFile( file, &io, info, size, FileDispositionInformation );
2797 break;
2798 case FileIoPriorityHintInfo:
2799 status = NtSetInformationFile( file, &io, info, size, FileIoPriorityHintInformation );
2800 break;
2801 case FileStandardInfo:
2802 case FileCompressionInfo:
2803 case FileAttributeTagInfo:
2804 case FileRemoteProtocolInfo:
2805 default:
2806 SetLastError( ERROR_INVALID_PARAMETER );
2807 return FALSE;
2809 return set_ntstatus( status );
2813 /***********************************************************************
2814 * SetFilePointer (kernelbase.@)
2816 DWORD WINAPI DECLSPEC_HOTPATCH SetFilePointer( HANDLE file, LONG distance, LONG *highword, DWORD method )
2818 LARGE_INTEGER dist, newpos;
2820 if (highword)
2822 dist.u.LowPart = distance;
2823 dist.u.HighPart = *highword;
2825 else dist.QuadPart = distance;
2827 if (!SetFilePointerEx( file, dist, &newpos, method )) return INVALID_SET_FILE_POINTER;
2829 if (highword) *highword = newpos.u.HighPart;
2830 if (newpos.u.LowPart == INVALID_SET_FILE_POINTER) SetLastError( 0 );
2831 return newpos.u.LowPart;
2835 /***********************************************************************
2836 * SetFilePointerEx (kernelbase.@)
2838 BOOL WINAPI DECLSPEC_HOTPATCH SetFilePointerEx( HANDLE file, LARGE_INTEGER distance,
2839 LARGE_INTEGER *newpos, DWORD method )
2841 LONGLONG pos;
2842 IO_STATUS_BLOCK io;
2843 FILE_POSITION_INFORMATION info;
2844 FILE_END_OF_FILE_INFORMATION eof;
2846 switch(method)
2848 case FILE_BEGIN:
2849 pos = distance.QuadPart;
2850 break;
2851 case FILE_CURRENT:
2852 if (NtQueryInformationFile( file, &io, &info, sizeof(info), FilePositionInformation ))
2853 goto error;
2854 pos = info.CurrentByteOffset.QuadPart + distance.QuadPart;
2855 break;
2856 case FILE_END:
2857 if (NtQueryInformationFile( file, &io, &eof, sizeof(eof), FileEndOfFileInformation ))
2858 goto error;
2859 pos = eof.EndOfFile.QuadPart + distance.QuadPart;
2860 break;
2861 default:
2862 SetLastError( ERROR_INVALID_PARAMETER );
2863 return FALSE;
2866 if (pos < 0)
2868 SetLastError( ERROR_NEGATIVE_SEEK );
2869 return FALSE;
2872 info.CurrentByteOffset.QuadPart = pos;
2873 if (!NtSetInformationFile( file, &io, &info, sizeof(info), FilePositionInformation ))
2875 if (newpos) newpos->QuadPart = pos;
2876 return TRUE;
2879 error:
2880 return set_ntstatus( io.u.Status );
2884 /***********************************************************************
2885 * SetFileTime (kernelbase.@)
2887 BOOL WINAPI DECLSPEC_HOTPATCH SetFileTime( HANDLE file, const FILETIME *ctime,
2888 const FILETIME *atime, const FILETIME *mtime )
2890 FILE_BASIC_INFORMATION info;
2891 IO_STATUS_BLOCK io;
2893 memset( &info, 0, sizeof(info) );
2894 if (ctime)
2896 info.CreationTime.u.HighPart = ctime->dwHighDateTime;
2897 info.CreationTime.u.LowPart = ctime->dwLowDateTime;
2899 if (atime)
2901 info.LastAccessTime.u.HighPart = atime->dwHighDateTime;
2902 info.LastAccessTime.u.LowPart = atime->dwLowDateTime;
2904 if (mtime)
2906 info.LastWriteTime.u.HighPart = mtime->dwHighDateTime;
2907 info.LastWriteTime.u.LowPart = mtime->dwLowDateTime;
2910 return set_ntstatus( NtSetInformationFile( file, &io, &info, sizeof(info), FileBasicInformation ));
2914 /***********************************************************************
2915 * SetFileValidData (kernelbase.@)
2917 BOOL WINAPI DECLSPEC_HOTPATCH SetFileValidData( HANDLE file, LONGLONG length )
2919 FILE_VALID_DATA_LENGTH_INFORMATION info;
2920 IO_STATUS_BLOCK io;
2922 info.ValidDataLength.QuadPart = length;
2923 return set_ntstatus( NtSetInformationFile( file, &io, &info, sizeof(info),
2924 FileValidDataLengthInformation ));
2928 /**************************************************************************
2929 * UnlockFile (kernelbase.@)
2931 BOOL WINAPI DECLSPEC_HOTPATCH UnlockFile( HANDLE file, DWORD offset_low, DWORD offset_high,
2932 DWORD count_low, DWORD count_high )
2934 LARGE_INTEGER count, offset;
2936 count.u.LowPart = count_low;
2937 count.u.HighPart = count_high;
2938 offset.u.LowPart = offset_low;
2939 offset.u.HighPart = offset_high;
2940 return set_ntstatus( NtUnlockFile( file, NULL, &offset, &count, NULL ));
2944 /**************************************************************************
2945 * UnlockFileEx (kernelbase.@)
2947 BOOL WINAPI DECLSPEC_HOTPATCH UnlockFileEx( HANDLE file, DWORD reserved,
2948 DWORD count_low, DWORD count_high, LPOVERLAPPED overlapped )
2950 if (reserved)
2952 SetLastError( ERROR_INVALID_PARAMETER );
2953 return FALSE;
2955 if (overlapped->hEvent) FIXME("Unimplemented overlapped operation\n");
2957 return UnlockFile( file, overlapped->u.s.Offset, overlapped->u.s.OffsetHigh, count_low, count_high );
2961 /***********************************************************************
2962 * WriteFile (kernelbase.@)
2964 BOOL WINAPI DECLSPEC_HOTPATCH WriteFile( HANDLE file, LPCVOID buffer, DWORD count,
2965 LPDWORD result, LPOVERLAPPED overlapped )
2967 HANDLE event = NULL;
2968 LARGE_INTEGER offset;
2969 PLARGE_INTEGER poffset = NULL;
2970 NTSTATUS status;
2971 IO_STATUS_BLOCK iosb;
2972 PIO_STATUS_BLOCK piosb = &iosb;
2973 LPVOID cvalue = NULL;
2975 TRACE( "%p %p %d %p %p\n", file, buffer, count, result, overlapped );
2977 if (overlapped)
2979 offset.u.LowPart = overlapped->u.s.Offset;
2980 offset.u.HighPart = overlapped->u.s.OffsetHigh;
2981 poffset = &offset;
2982 event = overlapped->hEvent;
2983 piosb = (PIO_STATUS_BLOCK)overlapped;
2984 if (((ULONG_PTR)event & 1) == 0) cvalue = overlapped;
2986 else piosb->Information = 0;
2987 piosb->u.Status = STATUS_PENDING;
2989 status = NtWriteFile( file, event, NULL, cvalue, piosb, buffer, count, poffset, NULL );
2991 if (status == STATUS_PENDING && !overlapped)
2993 WaitForSingleObject( file, INFINITE );
2994 status = piosb->u.Status;
2997 if (result) *result = overlapped && status ? 0 : piosb->Information;
2999 if (status && status != STATUS_TIMEOUT)
3001 SetLastError( RtlNtStatusToDosError(status) );
3002 return FALSE;
3004 return TRUE;
3008 /***********************************************************************
3009 * WriteFileEx (kernelbase.@)
3011 BOOL WINAPI DECLSPEC_HOTPATCH WriteFileEx( HANDLE file, LPCVOID buffer,
3012 DWORD count, LPOVERLAPPED overlapped,
3013 LPOVERLAPPED_COMPLETION_ROUTINE completion )
3015 LARGE_INTEGER offset;
3016 NTSTATUS status;
3017 PIO_STATUS_BLOCK io;
3019 TRACE( "%p %p %d %p %p\n", file, buffer, count, overlapped, completion );
3021 if (!overlapped)
3023 SetLastError( ERROR_INVALID_PARAMETER );
3024 return FALSE;
3026 offset.u.LowPart = overlapped->u.s.Offset;
3027 offset.u.HighPart = overlapped->u.s.OffsetHigh;
3029 io = (PIO_STATUS_BLOCK)overlapped;
3030 io->u.Status = STATUS_PENDING;
3031 io->Information = 0;
3033 status = NtWriteFile( file, NULL, read_write_apc, completion, io, buffer, count, &offset, NULL );
3034 if (status == STATUS_PENDING) return TRUE;
3035 return set_ntstatus( status );
3039 /***********************************************************************
3040 * WriteFileGather (kernelbase.@)
3042 BOOL WINAPI DECLSPEC_HOTPATCH WriteFileGather( HANDLE file, FILE_SEGMENT_ELEMENT *segments, DWORD count,
3043 LPDWORD reserved, LPOVERLAPPED overlapped )
3045 PIO_STATUS_BLOCK io;
3046 LARGE_INTEGER offset;
3047 void *cvalue = NULL;
3049 TRACE( "%p %p %u %p\n", file, segments, count, overlapped );
3051 offset.u.LowPart = overlapped->u.s.Offset;
3052 offset.u.HighPart = overlapped->u.s.OffsetHigh;
3053 if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped;
3054 io = (PIO_STATUS_BLOCK)overlapped;
3055 io->u.Status = STATUS_PENDING;
3056 io->Information = 0;
3058 return set_ntstatus( NtWriteFileGather( file, overlapped->hEvent, NULL, cvalue,
3059 io, segments, count, &offset, NULL ));
3063 /***********************************************************************
3064 * Operations on file times
3065 ***********************************************************************/
3068 /*********************************************************************
3069 * CompareFileTime (kernelbase.@)
3071 INT WINAPI DECLSPEC_HOTPATCH CompareFileTime( const FILETIME *x, const FILETIME *y )
3073 if (!x || !y) return -1;
3074 if (x->dwHighDateTime > y->dwHighDateTime) return 1;
3075 if (x->dwHighDateTime < y->dwHighDateTime) return -1;
3076 if (x->dwLowDateTime > y->dwLowDateTime) return 1;
3077 if (x->dwLowDateTime < y->dwLowDateTime) return -1;
3078 return 0;
3082 /*********************************************************************
3083 * FileTimeToLocalFileTime (kernelbase.@)
3085 BOOL WINAPI DECLSPEC_HOTPATCH FileTimeToLocalFileTime( const FILETIME *utc, FILETIME *local )
3087 return set_ntstatus( RtlSystemTimeToLocalTime( (const LARGE_INTEGER *)utc, (LARGE_INTEGER *)local ));
3091 /*********************************************************************
3092 * FileTimeToSystemTime (kernelbase.@)
3094 BOOL WINAPI DECLSPEC_HOTPATCH FileTimeToSystemTime( const FILETIME *ft, SYSTEMTIME *systime )
3096 TIME_FIELDS tf;
3098 RtlTimeToTimeFields( (const LARGE_INTEGER *)ft, &tf );
3099 systime->wYear = tf.Year;
3100 systime->wMonth = tf.Month;
3101 systime->wDay = tf.Day;
3102 systime->wHour = tf.Hour;
3103 systime->wMinute = tf.Minute;
3104 systime->wSecond = tf.Second;
3105 systime->wMilliseconds = tf.Milliseconds;
3106 systime->wDayOfWeek = tf.Weekday;
3107 return TRUE;
3111 /*********************************************************************
3112 * GetLocalTime (kernelbase.@)
3114 void WINAPI DECLSPEC_HOTPATCH GetLocalTime( SYSTEMTIME *systime )
3116 LARGE_INTEGER ft, ft2;
3118 NtQuerySystemTime( &ft );
3119 RtlSystemTimeToLocalTime( &ft, &ft2 );
3120 FileTimeToSystemTime( (FILETIME *)&ft2, systime );
3124 /*********************************************************************
3125 * GetSystemTime (kernelbase.@)
3127 void WINAPI DECLSPEC_HOTPATCH GetSystemTime( SYSTEMTIME *systime )
3129 LARGE_INTEGER ft;
3131 NtQuerySystemTime( &ft );
3132 FileTimeToSystemTime( (FILETIME *)&ft, systime );
3136 /***********************************************************************
3137 * GetSystemTimeAsFileTime (kernelbase.@)
3139 void WINAPI DECLSPEC_HOTPATCH GetSystemTimeAsFileTime( FILETIME *time )
3141 NtQuerySystemTime( (LARGE_INTEGER *)time );
3145 /***********************************************************************
3146 * GetSystemTimePreciseAsFileTime (kernelbase.@)
3148 void WINAPI DECLSPEC_HOTPATCH GetSystemTimePreciseAsFileTime( FILETIME *time )
3150 LARGE_INTEGER t;
3152 t.QuadPart = RtlGetSystemTimePrecise();
3153 time->dwLowDateTime = t.u.LowPart;
3154 time->dwHighDateTime = t.u.HighPart;
3158 /*********************************************************************
3159 * LocalFileTimeToFileTime (kernelbase.@)
3161 BOOL WINAPI DECLSPEC_HOTPATCH LocalFileTimeToFileTime( const FILETIME *local, FILETIME *utc )
3163 return set_ntstatus( RtlLocalTimeToSystemTime( (const LARGE_INTEGER *)local, (LARGE_INTEGER *)utc ));
3167 /***********************************************************************
3168 * SetLocalTime (kernelbase.@)
3170 BOOL WINAPI DECLSPEC_HOTPATCH SetLocalTime( const SYSTEMTIME *systime )
3172 FILETIME ft;
3173 LARGE_INTEGER st;
3175 if (!SystemTimeToFileTime( systime, &ft )) return FALSE;
3176 RtlLocalTimeToSystemTime( (LARGE_INTEGER *)&ft, &st );
3177 return set_ntstatus( NtSetSystemTime( &st, NULL ));
3181 /***********************************************************************
3182 * SetSystemTime (kernelbase.@)
3184 BOOL WINAPI DECLSPEC_HOTPATCH SetSystemTime( const SYSTEMTIME *systime )
3186 FILETIME ft;
3188 if (!SystemTimeToFileTime( systime, &ft )) return FALSE;
3189 return set_ntstatus( NtSetSystemTime( (LARGE_INTEGER *)&ft, NULL ));
3193 /*********************************************************************
3194 * SystemTimeToFileTime (kernelbase.@)
3196 BOOL WINAPI DECLSPEC_HOTPATCH SystemTimeToFileTime( const SYSTEMTIME *systime, FILETIME *ft )
3198 TIME_FIELDS tf;
3200 tf.Year = systime->wYear;
3201 tf.Month = systime->wMonth;
3202 tf.Day = systime->wDay;
3203 tf.Hour = systime->wHour;
3204 tf.Minute = systime->wMinute;
3205 tf.Second = systime->wSecond;
3206 tf.Milliseconds = systime->wMilliseconds;
3207 if (RtlTimeFieldsToTime( &tf, (LARGE_INTEGER *)ft )) return TRUE;
3208 SetLastError( ERROR_INVALID_PARAMETER );
3209 return FALSE;
3213 /***********************************************************************
3214 * I/O controls
3215 ***********************************************************************/
3218 static void dump_dcb( const DCB *dcb )
3220 TRACE( "size=%d rate=%d fParity=%d Parity=%d stopbits=%d %sIXON %sIXOFF CTS=%d RTS=%d DSR=%d DTR=%d %sCRTSCTS\n",
3221 dcb->ByteSize, dcb->BaudRate, dcb->fParity, dcb->Parity,
3222 (dcb->StopBits == ONESTOPBIT) ? 1 : (dcb->StopBits == TWOSTOPBITS) ? 2 : 0,
3223 dcb->fOutX ? "" : "~", dcb->fInX ? "" : "~",
3224 dcb->fOutxCtsFlow, dcb->fRtsControl, dcb->fOutxDsrFlow, dcb->fDtrControl,
3225 (dcb->fOutxCtsFlow || dcb->fRtsControl == RTS_CONTROL_HANDSHAKE) ? "" : "~" );
3228 /*****************************************************************************
3229 * ClearCommBreak (kernelbase.@)
3231 BOOL WINAPI DECLSPEC_HOTPATCH ClearCommBreak( HANDLE handle )
3233 return EscapeCommFunction( handle, CLRBREAK );
3237 /*****************************************************************************
3238 * ClearCommError (kernelbase.@)
3240 BOOL WINAPI DECLSPEC_HOTPATCH ClearCommError( HANDLE handle, DWORD *errors, COMSTAT *stat )
3242 SERIAL_STATUS ss;
3244 if (!DeviceIoControl( handle, IOCTL_SERIAL_GET_COMMSTATUS, NULL, 0, &ss, sizeof(ss), NULL, NULL ))
3245 return FALSE;
3247 TRACE( "status %#x,%#x, in %u, out %u, eof %d, wait %d\n", ss.Errors, ss.HoldReasons,
3248 ss.AmountInInQueue, ss.AmountInOutQueue, ss.EofReceived, ss.WaitForImmediate );
3250 if (errors)
3252 *errors = 0;
3253 if (ss.Errors & SERIAL_ERROR_BREAK) *errors |= CE_BREAK;
3254 if (ss.Errors & SERIAL_ERROR_FRAMING) *errors |= CE_FRAME;
3255 if (ss.Errors & SERIAL_ERROR_OVERRUN) *errors |= CE_OVERRUN;
3256 if (ss.Errors & SERIAL_ERROR_QUEUEOVERRUN) *errors |= CE_RXOVER;
3257 if (ss.Errors & SERIAL_ERROR_PARITY) *errors |= CE_RXPARITY;
3259 if (stat)
3261 stat->fCtsHold = !!(ss.HoldReasons & SERIAL_TX_WAITING_FOR_CTS);
3262 stat->fDsrHold = !!(ss.HoldReasons & SERIAL_TX_WAITING_FOR_DSR);
3263 stat->fRlsdHold = !!(ss.HoldReasons & SERIAL_TX_WAITING_FOR_DCD);
3264 stat->fXoffHold = !!(ss.HoldReasons & SERIAL_TX_WAITING_FOR_XON);
3265 stat->fXoffSent = !!(ss.HoldReasons & SERIAL_TX_WAITING_XOFF_SENT);
3266 stat->fEof = !!ss.EofReceived;
3267 stat->fTxim = !!ss.WaitForImmediate;
3268 stat->cbInQue = ss.AmountInInQueue;
3269 stat->cbOutQue = ss.AmountInOutQueue;
3271 return TRUE;
3275 /****************************************************************************
3276 * DeviceIoControl (kernelbase.@)
3278 BOOL WINAPI DECLSPEC_HOTPATCH DeviceIoControl( HANDLE handle, DWORD code, void *in_buff, DWORD in_count,
3279 void *out_buff, DWORD out_count, DWORD *returned,
3280 OVERLAPPED *overlapped )
3282 IO_STATUS_BLOCK iosb, *piosb = &iosb;
3283 void *cvalue = NULL;
3284 HANDLE event = 0;
3285 NTSTATUS status;
3287 TRACE( "(%p,%x,%p,%d,%p,%d,%p,%p)\n",
3288 handle, code, in_buff, in_count, out_buff, out_count, returned, overlapped );
3290 if (overlapped)
3292 piosb = (IO_STATUS_BLOCK *)overlapped;
3293 if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped;
3294 event = overlapped->hEvent;
3295 overlapped->Internal = STATUS_PENDING;
3296 overlapped->InternalHigh = 0;
3299 if (HIWORD(code) == FILE_DEVICE_FILE_SYSTEM)
3300 status = NtFsControlFile( handle, event, NULL, cvalue, piosb, code,
3301 in_buff, in_count, out_buff, out_count );
3302 else
3303 status = NtDeviceIoControlFile( handle, event, NULL, cvalue, piosb, code,
3304 in_buff, in_count, out_buff, out_count );
3306 if (returned) *returned = piosb->Information;
3307 return set_ntstatus( status );
3311 /*****************************************************************************
3312 * EscapeCommFunction (kernelbase.@)
3314 BOOL WINAPI DECLSPEC_HOTPATCH EscapeCommFunction( HANDLE handle, DWORD func )
3316 static const DWORD ioctls[] =
3319 IOCTL_SERIAL_SET_XOFF, /* SETXOFF */
3320 IOCTL_SERIAL_SET_XON, /* SETXON */
3321 IOCTL_SERIAL_SET_RTS, /* SETRTS */
3322 IOCTL_SERIAL_CLR_RTS, /* CLRRTS */
3323 IOCTL_SERIAL_SET_DTR, /* SETDTR */
3324 IOCTL_SERIAL_CLR_DTR, /* CLRDTR */
3325 IOCTL_SERIAL_RESET_DEVICE, /* RESETDEV */
3326 IOCTL_SERIAL_SET_BREAK_ON, /* SETBREAK */
3327 IOCTL_SERIAL_SET_BREAK_OFF /* CLRBREAK */
3330 if (func >= ARRAY_SIZE(ioctls) || !ioctls[func])
3332 SetLastError( ERROR_INVALID_PARAMETER );
3333 return FALSE;
3335 return DeviceIoControl( handle, ioctls[func], NULL, 0, NULL, 0, NULL, NULL );
3339 /***********************************************************************
3340 * GetCommConfig (kernelbase.@)
3342 BOOL WINAPI DECLSPEC_HOTPATCH GetCommConfig( HANDLE handle, COMMCONFIG *config, DWORD *size )
3344 if (!config) return FALSE;
3346 TRACE( "(%p, %p, %p %u)\n", handle, config, size, *size );
3348 if (*size < sizeof(COMMCONFIG))
3350 *size = sizeof(COMMCONFIG);
3351 return FALSE;
3353 *size = sizeof(COMMCONFIG);
3354 config->dwSize = sizeof(COMMCONFIG);
3355 config->wVersion = 1;
3356 config->wReserved = 0;
3357 config->dwProviderSubType = PST_RS232;
3358 config->dwProviderOffset = 0;
3359 config->dwProviderSize = 0;
3360 return GetCommState( handle, &config->dcb );
3364 /*****************************************************************************
3365 * GetCommMask (kernelbase.@)
3367 BOOL WINAPI DECLSPEC_HOTPATCH GetCommMask( HANDLE handle, DWORD *mask )
3369 return DeviceIoControl( handle, IOCTL_SERIAL_GET_WAIT_MASK, NULL, 0, mask, sizeof(*mask),
3370 NULL, NULL );
3374 /***********************************************************************
3375 * GetCommModemStatus (kernelbase.@)
3377 BOOL WINAPI DECLSPEC_HOTPATCH GetCommModemStatus( HANDLE handle, DWORD *status )
3379 return DeviceIoControl( handle, IOCTL_SERIAL_GET_MODEMSTATUS, NULL, 0, status, sizeof(*status),
3380 NULL, NULL );
3384 /***********************************************************************
3385 * GetCommProperties (kernelbase.@)
3387 BOOL WINAPI DECLSPEC_HOTPATCH GetCommProperties( HANDLE handle, COMMPROP *prop )
3389 return DeviceIoControl( handle, IOCTL_SERIAL_GET_PROPERTIES, NULL, 0, prop, sizeof(*prop), NULL, NULL );
3393 /*****************************************************************************
3394 * GetCommState (kernelbase.@)
3396 BOOL WINAPI DECLSPEC_HOTPATCH GetCommState( HANDLE handle, DCB *dcb )
3398 SERIAL_BAUD_RATE sbr;
3399 SERIAL_LINE_CONTROL slc;
3400 SERIAL_HANDFLOW shf;
3401 SERIAL_CHARS sc;
3403 if (!dcb)
3405 SetLastError( ERROR_INVALID_PARAMETER );
3406 return FALSE;
3408 if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_BAUD_RATE, NULL, 0, &sbr, sizeof(sbr), NULL, NULL) ||
3409 !DeviceIoControl(handle, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &slc, sizeof(slc), NULL, NULL) ||
3410 !DeviceIoControl(handle, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, &shf, sizeof(shf), NULL, NULL) ||
3411 !DeviceIoControl(handle, IOCTL_SERIAL_GET_CHARS, NULL, 0, &sc, sizeof(sc), NULL, NULL))
3412 return FALSE;
3414 dcb->DCBlength = sizeof(*dcb);
3415 dcb->BaudRate = sbr.BaudRate;
3416 /* yes, they seem no never be (re)set on NT */
3417 dcb->fBinary = 1;
3418 dcb->fParity = 0;
3419 dcb->fOutxCtsFlow = !!(shf.ControlHandShake & SERIAL_CTS_HANDSHAKE);
3420 dcb->fOutxDsrFlow = !!(shf.ControlHandShake & SERIAL_DSR_HANDSHAKE);
3421 dcb->fDsrSensitivity = !!(shf.ControlHandShake & SERIAL_DSR_SENSITIVITY);
3422 dcb->fTXContinueOnXoff = !!(shf.FlowReplace & SERIAL_XOFF_CONTINUE);
3423 dcb->fOutX = !!(shf.FlowReplace & SERIAL_AUTO_TRANSMIT);
3424 dcb->fInX = !!(shf.FlowReplace & SERIAL_AUTO_RECEIVE);
3425 dcb->fErrorChar = !!(shf.FlowReplace & SERIAL_ERROR_CHAR);
3426 dcb->fNull = !!(shf.FlowReplace & SERIAL_NULL_STRIPPING);
3427 dcb->fAbortOnError = !!(shf.ControlHandShake & SERIAL_ERROR_ABORT);
3428 dcb->XonLim = shf.XonLimit;
3429 dcb->XoffLim = shf.XoffLimit;
3430 dcb->ByteSize = slc.WordLength;
3431 dcb->Parity = slc.Parity;
3432 dcb->StopBits = slc.StopBits;
3433 dcb->XonChar = sc.XonChar;
3434 dcb->XoffChar = sc.XoffChar;
3435 dcb->ErrorChar = sc.ErrorChar;
3436 dcb->EofChar = sc.EofChar;
3437 dcb->EvtChar = sc.EventChar;
3439 switch (shf.ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE))
3441 case SERIAL_DTR_CONTROL: dcb->fDtrControl = DTR_CONTROL_ENABLE; break;
3442 case SERIAL_DTR_HANDSHAKE: dcb->fDtrControl = DTR_CONTROL_HANDSHAKE; break;
3443 default: dcb->fDtrControl = DTR_CONTROL_DISABLE; break;
3445 switch (shf.FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
3447 case SERIAL_RTS_CONTROL: dcb->fRtsControl = RTS_CONTROL_ENABLE; break;
3448 case SERIAL_RTS_HANDSHAKE: dcb->fRtsControl = RTS_CONTROL_HANDSHAKE; break;
3449 case SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE:
3450 dcb->fRtsControl = RTS_CONTROL_TOGGLE; break;
3451 default: dcb->fRtsControl = RTS_CONTROL_DISABLE; break;
3453 dump_dcb( dcb );
3454 return TRUE;
3458 /*****************************************************************************
3459 * GetCommTimeouts (kernelbase.@)
3461 BOOL WINAPI DECLSPEC_HOTPATCH GetCommTimeouts( HANDLE handle, COMMTIMEOUTS *timeouts )
3463 if (!timeouts)
3465 SetLastError( ERROR_INVALID_PARAMETER );
3466 return FALSE;
3468 return DeviceIoControl( handle, IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, timeouts, sizeof(*timeouts),
3469 NULL, NULL );
3472 /********************************************************************
3473 * PurgeComm (kernelbase.@)
3475 BOOL WINAPI DECLSPEC_HOTPATCH PurgeComm(HANDLE handle, DWORD flags)
3477 return DeviceIoControl( handle, IOCTL_SERIAL_PURGE, &flags, sizeof(flags),
3478 NULL, 0, NULL, NULL );
3482 /*****************************************************************************
3483 * SetCommBreak (kernelbase.@)
3485 BOOL WINAPI DECLSPEC_HOTPATCH SetCommBreak( HANDLE handle )
3487 return EscapeCommFunction( handle, SETBREAK );
3491 /***********************************************************************
3492 * SetCommConfig (kernelbase.@)
3494 BOOL WINAPI DECLSPEC_HOTPATCH SetCommConfig( HANDLE handle, COMMCONFIG *config, DWORD size )
3496 TRACE( "(%p, %p, %u)\n", handle, config, size );
3497 return SetCommState( handle, &config->dcb );
3501 /*****************************************************************************
3502 * SetCommMask (kernelbase.@)
3504 BOOL WINAPI DECLSPEC_HOTPATCH SetCommMask( HANDLE handle, DWORD mask )
3506 return DeviceIoControl( handle, IOCTL_SERIAL_SET_WAIT_MASK, &mask, sizeof(mask),
3507 NULL, 0, NULL, NULL );
3511 /*****************************************************************************
3512 * SetCommState (kernelbase.@)
3514 BOOL WINAPI DECLSPEC_HOTPATCH SetCommState( HANDLE handle, DCB *dcb )
3516 SERIAL_BAUD_RATE sbr;
3517 SERIAL_LINE_CONTROL slc;
3518 SERIAL_HANDFLOW shf;
3519 SERIAL_CHARS sc;
3521 if (!dcb)
3523 SetLastError( ERROR_INVALID_PARAMETER );
3524 return FALSE;
3526 dump_dcb( dcb );
3528 sbr.BaudRate = dcb->BaudRate;
3529 slc.StopBits = dcb->StopBits;
3530 slc.Parity = dcb->Parity;
3531 slc.WordLength = dcb->ByteSize;
3532 shf.ControlHandShake = 0;
3533 shf.FlowReplace = 0;
3534 if (dcb->fOutxCtsFlow) shf.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
3535 if (dcb->fOutxDsrFlow) shf.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
3536 switch (dcb->fDtrControl)
3538 case DTR_CONTROL_DISABLE: break;
3539 case DTR_CONTROL_ENABLE: shf.ControlHandShake |= SERIAL_DTR_CONTROL; break;
3540 case DTR_CONTROL_HANDSHAKE: shf.ControlHandShake |= SERIAL_DTR_HANDSHAKE; break;
3541 default:
3542 SetLastError( ERROR_INVALID_PARAMETER );
3543 return FALSE;
3545 switch (dcb->fRtsControl)
3547 case RTS_CONTROL_DISABLE: break;
3548 case RTS_CONTROL_ENABLE: shf.FlowReplace |= SERIAL_RTS_CONTROL; break;
3549 case RTS_CONTROL_HANDSHAKE: shf.FlowReplace |= SERIAL_RTS_HANDSHAKE; break;
3550 case RTS_CONTROL_TOGGLE: shf.FlowReplace |= SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE; break;
3551 default:
3552 SetLastError( ERROR_INVALID_PARAMETER );
3553 return FALSE;
3555 if (dcb->fDsrSensitivity) shf.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
3556 if (dcb->fAbortOnError) shf.ControlHandShake |= SERIAL_ERROR_ABORT;
3557 if (dcb->fErrorChar) shf.FlowReplace |= SERIAL_ERROR_CHAR;
3558 if (dcb->fNull) shf.FlowReplace |= SERIAL_NULL_STRIPPING;
3559 if (dcb->fTXContinueOnXoff) shf.FlowReplace |= SERIAL_XOFF_CONTINUE;
3560 if (dcb->fOutX) shf.FlowReplace |= SERIAL_AUTO_TRANSMIT;
3561 if (dcb->fInX) shf.FlowReplace |= SERIAL_AUTO_RECEIVE;
3562 shf.XonLimit = dcb->XonLim;
3563 shf.XoffLimit = dcb->XoffLim;
3564 sc.EofChar = dcb->EofChar;
3565 sc.ErrorChar = dcb->ErrorChar;
3566 sc.BreakChar = 0;
3567 sc.EventChar = dcb->EvtChar;
3568 sc.XonChar = dcb->XonChar;
3569 sc.XoffChar = dcb->XoffChar;
3571 /* note: change DTR/RTS lines after setting the comm attributes,
3572 * so flow control does not interfere.
3574 return (DeviceIoControl( handle, IOCTL_SERIAL_SET_BAUD_RATE, &sbr, sizeof(sbr), NULL, 0, NULL, NULL ) &&
3575 DeviceIoControl( handle, IOCTL_SERIAL_SET_LINE_CONTROL, &slc, sizeof(slc), NULL, 0, NULL, NULL ) &&
3576 DeviceIoControl( handle, IOCTL_SERIAL_SET_HANDFLOW, &shf, sizeof(shf), NULL, 0, NULL, NULL ) &&
3577 DeviceIoControl( handle, IOCTL_SERIAL_SET_CHARS, &sc, sizeof(sc), NULL, 0, NULL, NULL ));
3581 /*****************************************************************************
3582 * SetCommTimeouts (kernelbase.@)
3584 BOOL WINAPI DECLSPEC_HOTPATCH SetCommTimeouts( HANDLE handle, COMMTIMEOUTS *timeouts )
3586 if (!timeouts)
3588 SetLastError( ERROR_INVALID_PARAMETER );
3589 return FALSE;
3591 return DeviceIoControl( handle, IOCTL_SERIAL_SET_TIMEOUTS, timeouts, sizeof(*timeouts),
3592 NULL, 0, NULL, NULL );
3596 /*****************************************************************************
3597 * SetupComm (kernelbase.@)
3599 BOOL WINAPI DECLSPEC_HOTPATCH SetupComm( HANDLE handle, DWORD in_size, DWORD out_size )
3601 SERIAL_QUEUE_SIZE sqs;
3603 sqs.InSize = in_size;
3604 sqs.OutSize = out_size;
3605 return DeviceIoControl( handle, IOCTL_SERIAL_SET_QUEUE_SIZE, &sqs, sizeof(sqs), NULL, 0, NULL, NULL );
3609 /*****************************************************************************
3610 * TransmitCommChar (kernelbase.@)
3612 BOOL WINAPI DECLSPEC_HOTPATCH TransmitCommChar( HANDLE handle, CHAR ch )
3614 return DeviceIoControl( handle, IOCTL_SERIAL_IMMEDIATE_CHAR, &ch, sizeof(ch), NULL, 0, NULL, NULL );
3618 /***********************************************************************
3619 * WaitCommEvent (kernelbase.@)
3621 BOOL WINAPI DECLSPEC_HOTPATCH WaitCommEvent( HANDLE handle, DWORD *events, OVERLAPPED *overlapped )
3623 return DeviceIoControl( handle, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0, events, sizeof(*events),
3624 NULL, overlapped );