2009-09-24 18:49:46 +02:00
/* Unit test suite for Ntdll directory functions
*
* Copyright 2007 Jeff Latimer
* Copyright 2007 Andrey Turkin
* Copyright 2008 Jeff Zaroyko
* Copyright 2009 Dan Kegel
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
*
* NOTES
* We use function pointers here as there is no import library for NTDLL on
* windows .
*/
# include <stdio.h>
# include <stdarg.h>
# include "ntstatus.h"
/* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro
* definition errors when we get to winnt . h
*/
# define WIN32_NO_STATUS
# include "wine/test.h"
2016-05-03 06:16:16 +02:00
# include "winnls.h"
2009-09-24 18:49:46 +02:00
# include "winternl.h"
static NTSTATUS ( WINAPI * pNtClose ) ( PHANDLE ) ;
static NTSTATUS ( WINAPI * pNtOpenFile ) ( PHANDLE , ACCESS_MASK , POBJECT_ATTRIBUTES , PIO_STATUS_BLOCK , ULONG , ULONG ) ;
static NTSTATUS ( WINAPI * pNtQueryDirectoryFile ) ( HANDLE , HANDLE , PIO_APC_ROUTINE , PVOID , PIO_STATUS_BLOCK ,
PVOID , ULONG , FILE_INFORMATION_CLASS , BOOLEAN , PUNICODE_STRING , BOOLEAN ) ;
2016-05-03 06:15:40 +02:00
static NTSTATUS ( WINAPI * pNtQueryInformationFile ) ( HANDLE , PIO_STATUS_BLOCK , PVOID , LONG , FILE_INFORMATION_CLASS ) ;
static NTSTATUS ( WINAPI * pNtSetInformationFile ) ( HANDLE , PIO_STATUS_BLOCK , PVOID , ULONG , FILE_INFORMATION_CLASS ) ;
2009-09-24 18:49:46 +02:00
static BOOLEAN ( WINAPI * pRtlCreateUnicodeStringFromAsciiz ) ( PUNICODE_STRING , LPCSTR ) ;
static BOOL ( WINAPI * pRtlDosPathNameToNtPathName_U ) ( LPCWSTR , PUNICODE_STRING , PWSTR * , CURDIR * ) ;
static VOID ( WINAPI * pRtlInitUnicodeString ) ( PUNICODE_STRING , LPCWSTR ) ;
2009-12-07 10:32:03 +01:00
static VOID ( WINAPI * pRtlFreeUnicodeString ) ( PUNICODE_STRING ) ;
2016-05-03 06:16:16 +02:00
static LONG ( WINAPI * pRtlCompareUnicodeString ) ( const UNICODE_STRING * , const UNICODE_STRING * , BOOLEAN ) ;
2009-09-24 18:49:46 +02:00
static NTSTATUS ( WINAPI * pRtlMultiByteToUnicodeN ) ( LPWSTR dst , DWORD dstlen , LPDWORD reslen ,
LPCSTR src , DWORD srclen ) ;
2009-10-28 10:54:22 +01:00
static NTSTATUS ( WINAPI * pRtlWow64EnableFsRedirection ) ( BOOLEAN enable ) ;
static NTSTATUS ( WINAPI * pRtlWow64EnableFsRedirectionEx ) ( ULONG disable , ULONG * old_value ) ;
2009-09-24 18:49:46 +02:00
2009-09-29 17:56:20 +02:00
/* The attribute sets to test */
2010-10-01 13:37:03 +02:00
static struct testfile_s {
2011-08-04 22:24:48 +02:00
BOOL todo ; /* set if it doesn't work on wine yet */
BOOL attr_done ; /* set if attributes were tested for this file already */
2009-09-29 17:56:20 +02:00
const DWORD attr ; /* desired attribute */
2016-05-03 06:01:29 +02:00
WCHAR name [ 20 ] ; /* filename to use */
2009-09-29 17:56:20 +02:00
const char * target ; /* what to point to (only for reparse pts) */
const char * description ; /* for error messages */
int nfound ; /* How many were found (expect 1) */
} testfiles [ ] = {
2016-05-03 06:01:29 +02:00
{ 0 , 0 , FILE_ATTRIBUTE_NORMAL , { ' l ' , ' o ' , ' n ' , ' g ' , ' f ' , ' i ' , ' l ' , ' e ' , ' n ' , ' a ' , ' m ' , ' e ' , ' . ' , ' t ' , ' m ' , ' p ' } , " normal " } ,
{ 0 , 0 , FILE_ATTRIBUTE_NORMAL , { ' n ' , ' . ' , ' t ' , ' m ' , ' p ' , } , " normal " } ,
{ 1 , 0 , FILE_ATTRIBUTE_HIDDEN , { ' h ' , ' . ' , ' t ' , ' m ' , ' p ' , } , " hidden " } ,
{ 1 , 0 , FILE_ATTRIBUTE_SYSTEM , { ' s ' , ' . ' , ' t ' , ' m ' , ' p ' , } , " system " } ,
{ 0 , 0 , FILE_ATTRIBUTE_DIRECTORY , { ' d ' , ' . ' , ' t ' , ' m ' , ' p ' , } , " directory " } ,
{ 0 , 0 , FILE_ATTRIBUTE_NORMAL , { 0xe9 , ' a ' , ' . ' , ' t ' , ' m ' , ' p ' } , " normal " } ,
{ 0 , 0 , FILE_ATTRIBUTE_NORMAL , { 0xc9 , ' b ' , ' . ' , ' t ' , ' m ' , ' p ' } , " normal " } ,
{ 0 , 0 , FILE_ATTRIBUTE_NORMAL , { ' e ' , ' a ' , ' . ' , ' t ' , ' m ' , ' p ' } , " normal " } ,
{ 0 , 0 , FILE_ATTRIBUTE_DIRECTORY , { ' . ' } , " . directory " } ,
{ 0 , 0 , FILE_ATTRIBUTE_DIRECTORY , { ' . ' , ' . ' } , " .. directory " }
2009-09-29 17:56:20 +02:00
} ;
2018-06-21 23:06:11 +02:00
static const int test_dir_count = ARRAY_SIZE ( testfiles ) ;
static const int max_test_dir_size = ARRAY_SIZE ( testfiles ) + 5 ; /* size of above plus some for .. etc */
2009-09-29 17:56:20 +02:00
2016-05-02 09:29:19 +02:00
static const WCHAR dummyW [ ] = { ' d ' , ' u ' , ' m ' , ' m ' , ' y ' , 0 } ;
2016-05-03 06:01:29 +02:00
static const WCHAR dotW [ ] = { ' . ' , 0 } ;
static const WCHAR dotdotW [ ] = { ' . ' , ' . ' , 0 } ;
static const WCHAR backslashW [ ] = { ' \\ ' , 0 } ;
2016-05-02 09:29:19 +02:00
2009-09-29 17:56:20 +02:00
/* Create a test directory full of attribute test files, clear counts */
2016-05-03 06:01:29 +02:00
static void set_up_attribute_test ( const WCHAR * testdir )
2009-09-29 17:56:20 +02:00
{
int i ;
2010-12-28 21:10:40 +01:00
BOOL ret ;
2009-09-29 17:56:20 +02:00
2016-05-03 06:01:29 +02:00
ret = CreateDirectoryW ( testdir , NULL ) ;
ok ( ret , " couldn't create dir %s, error %d \n " , wine_dbgstr_w ( testdir ) , GetLastError ( ) ) ;
2009-09-29 17:56:20 +02:00
2016-05-03 06:01:29 +02:00
for ( i = 0 ; i < test_dir_count ; i + + ) {
WCHAR buf [ MAX_PATH ] ;
2009-09-29 17:56:20 +02:00
2016-05-03 06:01:29 +02:00
if ( lstrcmpW ( testfiles [ i ] . name , dotW ) = = 0 | | lstrcmpW ( testfiles [ i ] . name , dotdotW ) = = 0 )
2011-07-17 01:48:15 +02:00
continue ;
2016-05-03 06:01:29 +02:00
lstrcpyW ( buf , testdir ) ;
lstrcatW ( buf , backslashW ) ;
lstrcatW ( buf , testfiles [ i ] . name ) ;
2009-09-29 17:56:20 +02:00
if ( testfiles [ i ] . attr & FILE_ATTRIBUTE_DIRECTORY ) {
2016-05-03 06:01:29 +02:00
ret = CreateDirectoryW ( buf , NULL ) ;
ok ( ret , " couldn't create dir %s, error %d \n " , wine_dbgstr_w ( buf ) , GetLastError ( ) ) ;
2009-09-29 17:56:20 +02:00
} else {
2016-05-03 06:01:29 +02:00
HANDLE h = CreateFileW ( buf ,
2009-09-29 17:56:20 +02:00
GENERIC_READ | GENERIC_WRITE ,
0 , NULL , CREATE_ALWAYS ,
testfiles [ i ] . attr , 0 ) ;
2016-05-03 06:01:29 +02:00
ok ( h ! = INVALID_HANDLE_VALUE , " failed to create temp file %s \n " , wine_dbgstr_w ( buf ) ) ;
2009-09-29 17:56:20 +02:00
CloseHandle ( h ) ;
}
}
}
2011-08-04 22:24:48 +02:00
static void reset_found_files ( void )
{
int i ;
2016-05-03 06:01:29 +02:00
for ( i = 0 ; i < test_dir_count ; i + + )
2011-08-04 22:24:48 +02:00
testfiles [ i ] . nfound = 0 ;
}
2009-09-29 17:56:20 +02:00
/* Remove the given test directory and the attribute test files, if any */
2016-05-03 06:01:29 +02:00
static void tear_down_attribute_test ( const WCHAR * testdir )
2009-09-29 17:56:20 +02:00
{
int i ;
2016-05-03 06:01:29 +02:00
for ( i = 0 ; i < test_dir_count ; i + + ) {
2009-09-29 17:56:20 +02:00
int ret ;
2016-05-03 06:01:29 +02:00
WCHAR buf [ MAX_PATH ] ;
if ( lstrcmpW ( testfiles [ i ] . name , dotW ) = = 0 | | lstrcmpW ( testfiles [ i ] . name , dotdotW ) = = 0 )
2011-07-17 01:48:15 +02:00
continue ;
2016-05-03 06:01:29 +02:00
lstrcpyW ( buf , testdir ) ;
lstrcatW ( buf , backslashW ) ;
lstrcatW ( buf , testfiles [ i ] . name ) ;
2009-09-29 17:56:20 +02:00
if ( testfiles [ i ] . attr & FILE_ATTRIBUTE_DIRECTORY ) {
2016-05-03 06:01:29 +02:00
ret = RemoveDirectoryW ( buf ) ;
2009-09-29 17:56:20 +02:00
ok ( ret | | ( GetLastError ( ) = = ERROR_PATH_NOT_FOUND ) ,
2016-05-03 06:01:29 +02:00
" Failed to rmdir %s, error %d \n " , wine_dbgstr_w ( buf ) , GetLastError ( ) ) ;
2009-09-29 17:56:20 +02:00
} else {
2016-05-03 06:01:29 +02:00
ret = DeleteFileW ( buf ) ;
2009-09-29 17:56:20 +02:00
ok ( ret | | ( GetLastError ( ) = = ERROR_PATH_NOT_FOUND ) ,
2016-05-03 06:01:29 +02:00
" Failed to rm %s, error %d \n " , wine_dbgstr_w ( buf ) , GetLastError ( ) ) ;
2009-09-29 17:56:20 +02:00
}
}
2016-05-03 06:01:29 +02:00
RemoveDirectoryW ( testdir ) ;
2009-09-29 17:56:20 +02:00
}
/* Match one found file against testfiles[], increment count if found */
static void tally_test_file ( FILE_BOTH_DIRECTORY_INFORMATION * dir_info )
{
int i ;
DWORD attribmask =
( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT ) ;
DWORD attrib = dir_info - > FileAttributes & attribmask ;
WCHAR * nameW = dir_info - > FileName ;
int namelen = dir_info - > FileNameLength / sizeof ( WCHAR ) ;
2016-05-03 06:01:29 +02:00
for ( i = 0 ; i < test_dir_count ; i + + ) {
int len = lstrlenW ( testfiles [ i ] . name ) ;
if ( namelen ! = len | | memcmp ( nameW , testfiles [ i ] . name , len * sizeof ( WCHAR ) ) )
2009-09-29 17:56:20 +02:00
continue ;
2011-08-04 22:24:48 +02:00
if ( ! testfiles [ i ] . attr_done ) {
2016-02-19 22:10:55 +01:00
todo_wine_if ( testfiles [ i ] . todo )
2016-05-03 06:01:29 +02:00
ok ( attrib = = ( testfiles [ i ] . attr & attribmask ) , " file %s: expected %s (%x), got %x (is your linux new enough?) \n " , wine_dbgstr_w ( testfiles [ i ] . name ) , testfiles [ i ] . description , testfiles [ i ] . attr , attrib ) ;
2011-08-04 22:24:48 +02:00
testfiles [ i ] . attr_done = TRUE ;
2009-09-29 17:56:20 +02:00
}
testfiles [ i ] . nfound + + ;
break ;
}
2016-05-03 06:01:29 +02:00
ok ( i < test_dir_count , " unexpected file found %s \n " , wine_dbgstr_wn ( dir_info - > FileName , namelen ) ) ;
2009-09-29 17:56:20 +02:00
}
2011-08-04 22:24:48 +02:00
static void test_flags_NtQueryDirectoryFile ( OBJECT_ATTRIBUTES * attr , const char * testdirA ,
2013-07-01 19:50:43 +02:00
UNICODE_STRING * mask ,
2011-08-04 22:24:48 +02:00
BOOLEAN single_entry , BOOLEAN restart_flag )
2009-09-24 18:49:46 +02:00
{
2016-05-02 09:29:19 +02:00
UNICODE_STRING dummy_mask ;
HANDLE dirh , new_dirh ;
2009-09-24 18:49:46 +02:00
IO_STATUS_BLOCK io ;
2013-07-01 19:50:43 +02:00
UINT data_pos , data_size ;
2009-09-24 18:49:46 +02:00
UINT data_len ; /* length of dir data */
BYTE data [ 8192 ] ; /* directory data */
FILE_BOTH_DIRECTORY_INFORMATION * dir_info ;
2016-04-28 09:44:25 +02:00
NTSTATUS status ;
2009-09-24 18:49:46 +02:00
int numfiles ;
2009-09-29 17:56:20 +02:00
int i ;
2009-09-24 18:49:46 +02:00
2011-08-04 22:24:48 +02:00
reset_found_files ( ) ;
2016-05-02 09:29:19 +02:00
pRtlInitUnicodeString ( & dummy_mask , dummyW ) ;
2009-09-24 18:49:46 +02:00
2013-07-01 19:50:43 +02:00
data_size = mask ? offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 256 ] ) : sizeof ( data ) ;
2009-09-29 17:56:20 +02:00
/* Read the directory and note which files are found */
2015-05-18 10:41:29 +02:00
status = pNtOpenFile ( & dirh , SYNCHRONIZE | FILE_LIST_DIRECTORY , attr , & io , FILE_SHARE_READ ,
2009-09-24 18:49:46 +02:00
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE ) ;
2009-09-29 17:56:20 +02:00
ok ( status = = STATUS_SUCCESS , " failed to open dir '%s', ret 0x%x, error %d \n " , testdirA , status , GetLastError ( ) ) ;
2009-09-24 18:49:46 +02:00
if ( status ! = STATUS_SUCCESS ) {
skip ( " can't test if we can't open the directory \n " ) ;
2011-08-04 22:24:48 +02:00
return ;
2009-09-24 18:49:46 +02:00
}
2016-04-28 09:44:25 +02:00
U ( io ) . Status = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , NULL , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , single_entry , mask , restart_flag ) ;
ok ( status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , status ) ;
2013-07-01 19:50:43 +02:00
ok ( U ( io ) . Status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , U ( io ) . Status ) ;
2009-09-24 18:49:46 +02:00
data_len = io . Information ;
ok ( data_len > = sizeof ( FILE_BOTH_DIRECTORY_INFORMATION ) , " not enough data in directory \n " ) ;
2016-05-02 09:29:19 +02:00
DuplicateHandle ( GetCurrentProcess ( ) , dirh , GetCurrentProcess ( ) , & new_dirh ,
0 , FALSE , DUPLICATE_SAME_ACCESS ) ;
pNtClose ( dirh ) ;
2009-09-24 18:49:46 +02:00
data_pos = 0 ;
numfiles = 0 ;
2009-09-29 17:56:20 +02:00
while ( ( data_pos < data_len ) & & ( numfiles < max_test_dir_size ) ) {
2009-09-24 18:49:46 +02:00
dir_info = ( FILE_BOTH_DIRECTORY_INFORMATION * ) ( data + data_pos ) ;
2009-09-29 17:56:20 +02:00
tally_test_file ( dir_info ) ;
2009-09-24 18:49:46 +02:00
if ( dir_info - > NextEntryOffset = = 0 ) {
2016-04-28 09:44:25 +02:00
U ( io ) . Status = 0xdeadbeef ;
2016-05-02 09:29:19 +02:00
status = pNtQueryDirectoryFile ( new_dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , single_entry , & dummy_mask , FALSE ) ;
2016-04-28 09:44:25 +02:00
ok ( U ( io ) . Status = = status , " wrong status %x / %x \n " , status , U ( io ) . Status ) ;
if ( status = = STATUS_NO_MORE_FILES ) break ;
ok ( status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , status ) ;
2009-09-24 18:49:46 +02:00
data_len = io . Information ;
if ( data_len < sizeof ( FILE_BOTH_DIRECTORY_INFORMATION ) )
break ;
data_pos = 0 ;
} else {
data_pos + = dir_info - > NextEntryOffset ;
}
numfiles + + ;
}
2009-09-29 17:56:20 +02:00
ok ( numfiles < max_test_dir_size , " too many loops \n " ) ;
2013-07-01 19:50:43 +02:00
if ( mask )
2016-05-03 06:01:29 +02:00
for ( i = 0 ; i < test_dir_count ; i + + )
ok ( testfiles [ i ] . nfound = = ( testfiles [ i ] . name = = mask - > Buffer ) ,
2013-07-01 19:50:43 +02:00
" Wrong number %d of %s files found (single_entry=%d,mask=%s) \n " ,
testfiles [ i ] . nfound , testfiles [ i ] . description , single_entry ,
wine_dbgstr_wn ( mask - > Buffer , mask - > Length / sizeof ( WCHAR ) ) ) ;
else
2016-05-03 06:01:29 +02:00
for ( i = 0 ; i < test_dir_count ; i + + )
2013-07-01 19:50:43 +02:00
ok ( testfiles [ i ] . nfound = = 1 , " Wrong number %d of %s files found (single_entry=%d,restart=%d) \n " ,
testfiles [ i ] . nfound , testfiles [ i ] . description , single_entry , restart_flag ) ;
2016-05-02 09:29:19 +02:00
pNtClose ( new_dirh ) ;
2011-08-04 22:24:48 +02:00
}
2016-05-03 06:16:16 +02:00
static void test_directory_sort ( const WCHAR * testdir )
{
OBJECT_ATTRIBUTES attr ;
UNICODE_STRING ntdirname ;
IO_STATUS_BLOCK io ;
UINT data_pos , data_len , count ;
BYTE data [ 8192 ] ;
WCHAR prev [ MAX_PATH ] , name [ MAX_PATH ] ;
UNICODE_STRING prev_str , name_str ;
FILE_BOTH_DIRECTORY_INFORMATION * info ;
NTSTATUS status ;
HANDLE handle ;
int res ;
if ( ! pRtlDosPathNameToNtPathName_U ( testdir , & ntdirname , NULL , NULL ) )
{
ok ( 0 , " RtlDosPathNametoNtPathName_U failed \n " ) ;
return ;
}
InitializeObjectAttributes ( & attr , & ntdirname , OBJ_CASE_INSENSITIVE , 0 , NULL ) ;
status = pNtOpenFile ( & handle , SYNCHRONIZE | FILE_LIST_DIRECTORY , & attr , & io , FILE_SHARE_READ ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE ) ;
ok ( status = = STATUS_SUCCESS , " failed to open dir %s \n " , wine_dbgstr_w ( testdir ) ) ;
U ( io ) . Status = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( handle , NULL , NULL , NULL , & io , data , sizeof ( data ) ,
FileBothDirectoryInformation , FALSE , NULL , TRUE ) ;
ok ( status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , U ( io ) . Status ) ;
data_len = io . Information ;
ok ( data_len > = sizeof ( FILE_BOTH_DIRECTORY_INFORMATION ) , " not enough data in directory \n " ) ;
data_pos = 0 ;
count = 0 ;
while ( data_pos < data_len )
{
info = ( FILE_BOTH_DIRECTORY_INFORMATION * ) ( data + data_pos ) ;
memcpy ( name , info - > FileName , info - > FileNameLength ) ;
name [ info - > FileNameLength / sizeof ( WCHAR ) ] = 0 ;
switch ( count )
{
case 0 : /* first entry must be '.' */
ok ( ! lstrcmpW ( name , dotW ) , " wrong name %s \n " , wine_dbgstr_w ( name ) ) ;
break ;
case 1 : /* second entry must be '..' */
ok ( ! lstrcmpW ( name , dotdotW ) , " wrong name %s \n " , wine_dbgstr_w ( name ) ) ;
break ;
case 2 : /* nothing to compare against */
break ;
default :
pRtlInitUnicodeString ( & prev_str , prev ) ;
pRtlInitUnicodeString ( & name_str , name ) ;
res = pRtlCompareUnicodeString ( & prev_str , & name_str , TRUE ) ;
ok ( res < 0 , " wrong result %d %s %s \n " , res , wine_dbgstr_w ( prev ) , wine_dbgstr_w ( name ) ) ;
break ;
}
count + + ;
lstrcpyW ( prev , name ) ;
if ( info - > NextEntryOffset = = 0 )
{
U ( io ) . Status = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( handle , 0 , NULL , NULL , & io , data , sizeof ( data ) ,
FileBothDirectoryInformation , FALSE , NULL , FALSE ) ;
ok ( U ( io ) . Status = = status , " wrong status %x / %x \n " , status , U ( io ) . Status ) ;
if ( status = = STATUS_NO_MORE_FILES ) break ;
ok ( status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , status ) ;
data_len = io . Information ;
data_pos = 0 ;
}
else data_pos + = info - > NextEntryOffset ;
}
pNtClose ( handle ) ;
pRtlFreeUnicodeString ( & ntdirname ) ;
}
2016-05-04 09:05:35 +02:00
static void test_NtQueryDirectoryFile_classes ( HANDLE handle , UNICODE_STRING * mask )
{
IO_STATUS_BLOCK io ;
UINT data_size ;
ULONG data [ 256 ] ;
NTSTATUS status ;
int class ;
for ( class = 0 ; class < FileMaximumInformation ; class + + )
{
U ( io ) . Status = 0xdeadbeef ;
U ( io ) . Information = 0xdeadbeef ;
data_size = 0 ;
memset ( data , 0x55 , sizeof ( data ) ) ;
status = pNtQueryDirectoryFile ( handle , 0 , NULL , NULL , & io , data , data_size ,
class , FALSE , mask , TRUE ) ;
ok ( U ( io ) . Status = = 0xdeadbeef , " %u: wrong status %x \n " , class , U ( io ) . Status ) ;
ok ( U ( io ) . Information = = 0xdeadbeef , " %u: wrong info %lx \n " , class , U ( io ) . Information ) ;
ok ( data [ 0 ] = = 0x55555555 , " %u: wrong offset %x \n " , class , data [ 0 ] ) ;
switch ( class )
{
case FileIdGlobalTxDirectoryInformation :
2017-02-07 16:11:00 +01:00
case FileIdExtdDirectoryInformation :
case FileIdExtdBothDirectoryInformation :
2016-05-04 09:05:35 +02:00
if ( status = = STATUS_INVALID_INFO_CLASS | | status = = STATUS_NOT_IMPLEMENTED ) continue ;
/* fall through */
case FileDirectoryInformation :
case FileFullDirectoryInformation :
case FileBothDirectoryInformation :
case FileNamesInformation :
case FileIdBothDirectoryInformation :
case FileIdFullDirectoryInformation :
case FileObjectIdInformation :
case FileQuotaInformation :
case FileReparsePointInformation :
ok ( status = = STATUS_INFO_LENGTH_MISMATCH , " %u: wrong status %x \n " , class , status ) ;
break ;
default :
ok ( status = = STATUS_INVALID_INFO_CLASS | | status = = STATUS_NOT_IMPLEMENTED ,
" %u: wrong status %x \n " , class , status ) ;
continue ;
}
for ( data_size = 1 ; data_size < sizeof ( data ) ; data_size + + )
{
status = pNtQueryDirectoryFile ( handle , 0 , NULL , NULL , & io , data , data_size ,
class , FALSE , mask , TRUE ) ;
if ( status = = STATUS_BUFFER_OVERFLOW )
{
ok ( U ( io ) . Status = = STATUS_BUFFER_OVERFLOW , " %u: wrong status %x \n " , class , U ( io ) . Status ) ;
ok ( U ( io ) . Information = = data_size , " %u: wrong info %lx \n " , class , U ( io ) . Information ) ;
ok ( data [ 0 ] = = 0 , " %u: wrong offset %x \n " , class , data [ 0 ] ) ;
}
else
{
ok ( U ( io ) . Status = = 0xdeadbeef , " %u: wrong status %x \n " , class , U ( io ) . Status ) ;
ok ( U ( io ) . Information = = 0xdeadbeef , " %u: wrong info %lx \n " , class , U ( io ) . Information ) ;
ok ( data [ 0 ] = = 0x55555555 , " %u: wrong offset %x \n " , class , data [ 0 ] ) ;
}
if ( status ! = STATUS_INFO_LENGTH_MISMATCH ) break ;
}
switch ( class )
{
case FileDirectoryInformation :
ok ( status = = STATUS_BUFFER_OVERFLOW , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = ( ( offsetof ( FILE_DIRECTORY_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileFullDirectoryInformation :
ok ( status = = STATUS_BUFFER_OVERFLOW , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = ( ( offsetof ( FILE_FULL_DIRECTORY_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileBothDirectoryInformation :
ok ( status = = STATUS_BUFFER_OVERFLOW , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = ( ( offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileNamesInformation :
ok ( status = = STATUS_BUFFER_OVERFLOW , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = ( ( offsetof ( FILE_NAMES_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileIdBothDirectoryInformation :
ok ( status = = STATUS_BUFFER_OVERFLOW , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = ( ( offsetof ( FILE_ID_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileIdFullDirectoryInformation :
ok ( status = = STATUS_BUFFER_OVERFLOW , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = ( ( offsetof ( FILE_ID_FULL_DIRECTORY_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileIdGlobalTxDirectoryInformation :
ok ( status = = STATUS_BUFFER_OVERFLOW , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = ( ( offsetof ( FILE_ID_GLOBAL_TX_DIR_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileObjectIdInformation :
ok ( status = = STATUS_INVALID_INFO_CLASS , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = sizeof ( FILE_OBJECTID_INFORMATION ) , " %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileQuotaInformation :
ok ( status = = STATUS_INVALID_INFO_CLASS , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = sizeof ( FILE_QUOTA_INFORMATION ) , " %u: wrong size %u \n " , class , data_size ) ;
break ;
case FileReparsePointInformation :
ok ( status = = STATUS_INVALID_INFO_CLASS , " %u: wrong status %x \n " , class , status ) ;
ok ( data_size = = sizeof ( FILE_REPARSE_POINT_INFORMATION ) , " %u: wrong size %u \n " , class , data_size ) ;
break ;
}
}
}
2011-08-04 22:24:48 +02:00
static void test_NtQueryDirectoryFile ( void )
{
OBJECT_ATTRIBUTES attr ;
2015-12-21 18:42:04 +01:00
UNICODE_STRING ntdirname , mask ;
2020-06-12 14:20:16 +02:00
char testdirA [ MAX_PATH ] , buffer [ MAX_PATH ] ;
2011-08-04 22:24:48 +02:00
WCHAR testdirW [ MAX_PATH ] ;
2013-07-01 19:50:43 +02:00
int i ;
2015-12-21 18:42:04 +01:00
IO_STATUS_BLOCK io ;
WCHAR short_name [ 12 ] ;
UINT data_size ;
BYTE data [ 8192 ] ;
2016-04-28 09:44:25 +02:00
FILE_BOTH_DIRECTORY_INFORMATION * next , * fbdi = ( FILE_BOTH_DIRECTORY_INFORMATION * ) data ;
2016-05-03 06:15:40 +02:00
FILE_POSITION_INFORMATION pos_info ;
2016-05-04 09:05:35 +02:00
FILE_NAMES_INFORMATION * names ;
2016-04-28 09:44:25 +02:00
const WCHAR * filename = fbdi - > FileName ;
NTSTATUS status ;
2020-06-12 14:20:16 +02:00
HANDLE dirh , h ;
2011-08-04 22:24:48 +02:00
/* Clean up from prior aborted run, if any, then set up test files */
ok ( GetTempPathA ( MAX_PATH , testdirA ) , " couldn't get temp dir \n " ) ;
strcat ( testdirA , " NtQueryDirectoryFile.tmp " ) ;
pRtlMultiByteToUnicodeN ( testdirW , sizeof ( testdirW ) , NULL , testdirA , strlen ( testdirA ) + 1 ) ;
2016-05-03 06:01:29 +02:00
tear_down_attribute_test ( testdirW ) ;
set_up_attribute_test ( testdirW ) ;
2011-08-04 22:24:48 +02:00
if ( ! pRtlDosPathNameToNtPathName_U ( testdirW , & ntdirname , NULL , NULL ) )
{
ok ( 0 , " RtlDosPathNametoNtPathName_U failed \n " ) ;
goto done ;
}
InitializeObjectAttributes ( & attr , & ntdirname , OBJ_CASE_INSENSITIVE , 0 , NULL ) ;
2013-07-01 19:50:43 +02:00
test_flags_NtQueryDirectoryFile ( & attr , testdirA , NULL , FALSE , TRUE ) ;
test_flags_NtQueryDirectoryFile ( & attr , testdirA , NULL , FALSE , FALSE ) ;
test_flags_NtQueryDirectoryFile ( & attr , testdirA , NULL , TRUE , TRUE ) ;
test_flags_NtQueryDirectoryFile ( & attr , testdirA , NULL , TRUE , FALSE ) ;
2016-05-03 06:01:29 +02:00
for ( i = 0 ; i < test_dir_count ; i + + )
2013-07-01 19:50:43 +02:00
{
2016-05-03 06:01:29 +02:00
if ( testfiles [ i ] . name [ 0 ] = = ' . ' ) continue ; /* . and .. as masks are broken on Windows */
mask . Buffer = testfiles [ i ] . name ;
mask . Length = mask . MaximumLength = lstrlenW ( testfiles [ i ] . name ) * sizeof ( WCHAR ) ;
2013-07-01 19:50:43 +02:00
test_flags_NtQueryDirectoryFile ( & attr , testdirA , & mask , FALSE , TRUE ) ;
test_flags_NtQueryDirectoryFile ( & attr , testdirA , & mask , FALSE , FALSE ) ;
test_flags_NtQueryDirectoryFile ( & attr , testdirA , & mask , TRUE , TRUE ) ;
test_flags_NtQueryDirectoryFile ( & attr , testdirA , & mask , TRUE , FALSE ) ;
}
2011-08-04 22:24:48 +02:00
2015-12-21 18:42:04 +01:00
/* short path passed as mask */
status = pNtOpenFile ( & dirh , SYNCHRONIZE | FILE_LIST_DIRECTORY , & attr , & io , FILE_SHARE_READ ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE ) ;
ok ( status = = STATUS_SUCCESS , " failed to open dir '%s' \n " , testdirA ) ;
if ( status ! = STATUS_SUCCESS ) {
skip ( " can't test if we can't open the directory \n " ) ;
return ;
}
2016-05-03 06:15:40 +02:00
status = pNtQueryInformationFile ( dirh , & io , & pos_info , sizeof ( pos_info ) , FilePositionInformation ) ;
ok ( status = = STATUS_SUCCESS , " NtQueryInformationFile failed %x \n " , status ) ;
2017-08-07 01:31:31 +02:00
ok ( pos_info . CurrentByteOffset . QuadPart = = 0 , " wrong pos %s \n " ,
wine_dbgstr_longlong ( pos_info . CurrentByteOffset . QuadPart ) ) ;
2016-05-03 06:15:40 +02:00
pos_info . CurrentByteOffset . QuadPart = 0xbeef ;
status = pNtSetInformationFile ( dirh , & io , & pos_info , sizeof ( pos_info ) , FilePositionInformation ) ;
ok ( status = = STATUS_SUCCESS , " NtQueryInformationFile failed %x \n " , status ) ;
status = pNtQueryInformationFile ( dirh , & io , & pos_info , sizeof ( pos_info ) , FilePositionInformation ) ;
ok ( status = = STATUS_SUCCESS , " NtQueryInformationFile failed %x \n " , status ) ;
2017-08-07 01:31:31 +02:00
ok ( pos_info . CurrentByteOffset . QuadPart = = 0xbeef , " wrong pos %s \n " ,
wine_dbgstr_longlong ( pos_info . CurrentByteOffset . QuadPart ) ) ;
2016-05-03 06:15:40 +02:00
2016-05-03 06:01:29 +02:00
mask . Buffer = testfiles [ 0 ] . name ;
mask . Length = mask . MaximumLength = lstrlenW ( testfiles [ 0 ] . name ) * sizeof ( WCHAR ) ;
2015-12-21 18:42:04 +01:00
data_size = offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 256 ] ) ;
2016-04-28 09:44:25 +02:00
U ( io ) . Status = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , & mask , FALSE ) ;
ok ( status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , status ) ;
2015-12-21 18:42:04 +01:00
ok ( U ( io ) . Status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , U ( io ) . Status ) ;
ok ( fbdi - > ShortName [ 0 ] , " ShortName is empty \n " ) ;
2016-05-03 06:15:40 +02:00
status = pNtQueryInformationFile ( dirh , & io , & pos_info , sizeof ( pos_info ) , FilePositionInformation ) ;
ok ( status = = STATUS_SUCCESS , " NtQueryInformationFile failed %x \n " , status ) ;
2017-08-07 01:31:31 +02:00
ok ( pos_info . CurrentByteOffset . QuadPart = = 0xbeef , " wrong pos %s \n " ,
wine_dbgstr_longlong ( pos_info . CurrentByteOffset . QuadPart ) ) ;
2016-05-03 06:15:40 +02:00
2015-12-21 18:42:04 +01:00
mask . Length = mask . MaximumLength = fbdi - > ShortNameLength ;
memcpy ( short_name , fbdi - > ShortName , mask . Length ) ;
mask . Buffer = short_name ;
2016-04-28 09:44:25 +02:00
U ( io ) . Status = 0xdeadbeef ;
U ( io ) . Information = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , & mask , TRUE ) ;
ok ( status = = STATUS_SUCCESS , " failed to query directory status %x \n " , status ) ;
2015-12-21 18:42:04 +01:00
ok ( U ( io ) . Status = = STATUS_SUCCESS , " failed to query directory status %x \n " , U ( io ) . Status ) ;
2016-05-03 06:01:29 +02:00
ok ( U ( io ) . Information = = offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ lstrlenW ( testfiles [ 0 ] . name ) ] ) ,
2016-04-28 09:44:25 +02:00
" wrong info %lx \n " , U ( io ) . Information ) ;
2016-05-03 06:01:29 +02:00
ok ( fbdi - > FileNameLength = = lstrlenW ( testfiles [ 0 ] . name ) * sizeof ( WCHAR ) & &
! memcmp ( fbdi - > FileName , testfiles [ 0 ] . name , fbdi - > FileNameLength ) ,
2015-12-21 18:42:04 +01:00
" incorrect long file name: %s \n " , wine_dbgstr_wn ( fbdi - > FileName ,
fbdi - > FileNameLength / sizeof ( WCHAR ) ) ) ;
2016-05-03 06:15:40 +02:00
status = pNtQueryInformationFile ( dirh , & io , & pos_info , sizeof ( pos_info ) , FilePositionInformation ) ;
ok ( status = = STATUS_SUCCESS , " NtQueryInformationFile failed %x \n " , status ) ;
2017-08-07 01:31:31 +02:00
ok ( pos_info . CurrentByteOffset . QuadPart = = 0xbeef , " wrong pos %s \n " ,
wine_dbgstr_longlong ( pos_info . CurrentByteOffset . QuadPart ) ) ;
2016-05-03 06:15:40 +02:00
2016-04-28 09:44:25 +02:00
/* tests with short buffer */
memset ( data , 0x55 , data_size ) ;
U ( io ) . Status = 0xdeadbeef ;
U ( io ) . Information = 0xdeadbeef ;
data_size = offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , & mask , TRUE ) ;
ok ( status = = STATUS_BUFFER_OVERFLOW , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_BUFFER_OVERFLOW , " wrong status %x \n " , U ( io ) . Status ) ;
2016-05-02 09:29:19 +02:00
ok ( U ( io ) . Information = = data_size | | broken ( U ( io ) . Information = = 0 ) ,
2016-04-28 09:44:25 +02:00
" wrong info %lx \n " , U ( io ) . Information ) ;
2018-12-11 15:55:34 +01:00
ok ( fbdi - > NextEntryOffset = = 0 | | fbdi - > NextEntryOffset = = 0x55555555 , /* win10 >= 1709 */
" wrong offset %x \n " , fbdi - > NextEntryOffset ) ;
if ( ! fbdi - > NextEntryOffset )
{
ok ( fbdi - > FileNameLength = = lstrlenW ( testfiles [ 0 ] . name ) * sizeof ( WCHAR ) ,
" wrong length %x \n " , fbdi - > FileNameLength ) ;
ok ( filename [ 0 ] = = testfiles [ 0 ] . name [ 0 ] , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( fbdi - > FileName , fbdi - > FileNameLength / sizeof ( WCHAR ) ) ) ;
ok ( filename [ 1 ] = = 0x5555 , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( fbdi - > FileName , fbdi - > FileNameLength / sizeof ( WCHAR ) ) ) ;
}
2016-04-28 09:44:25 +02:00
2016-05-04 09:05:35 +02:00
test_NtQueryDirectoryFile_classes ( dirh , & mask ) ;
2016-05-02 09:29:19 +02:00
/* mask may or may not be ignored when restarting the search */
pRtlInitUnicodeString ( & mask , dummyW ) ;
U ( io ) . Status = 0xdeadbeef ;
data_size = offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 256 ] ) ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , & mask , TRUE ) ;
ok ( status = = STATUS_SUCCESS | | status = = STATUS_NO_MORE_FILES , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = status , " wrong status %x / %x \n " , U ( io ) . Status , status ) ;
if ( ! status )
2016-05-03 06:01:29 +02:00
ok ( fbdi - > FileNameLength = = lstrlenW ( testfiles [ 0 ] . name ) * sizeof ( WCHAR ) & &
! memcmp ( fbdi - > FileName , testfiles [ 0 ] . name , fbdi - > FileNameLength ) ,
2016-05-02 09:29:19 +02:00
" incorrect long file name: %s \n " ,
wine_dbgstr_wn ( fbdi - > FileName , fbdi - > FileNameLength / sizeof ( WCHAR ) ) ) ;
2016-04-28 09:44:25 +02:00
pNtClose ( dirh ) ;
status = pNtOpenFile ( & dirh , SYNCHRONIZE | FILE_LIST_DIRECTORY , & attr , & io , FILE_SHARE_READ ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE ) ;
ok ( status = = STATUS_SUCCESS , " failed to open dir '%s' \n " , testdirA ) ;
memset ( data , 0x55 , data_size ) ;
data_size = sizeof ( data ) ;
U ( io ) . Status = 0xdeadbeef ;
U ( io ) . Information = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , FALSE , NULL , TRUE ) ;
ok ( status = = STATUS_SUCCESS , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_SUCCESS , " wrong status %x \n " , U ( io ) . Status ) ;
ok ( U ( io ) . Information > 0 & & U ( io ) . Information < data_size , " wrong info %lx \n " , U ( io ) . Information ) ;
ok ( fbdi - > NextEntryOffset = = ( ( offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" wrong offset %x \n " , fbdi - > NextEntryOffset ) ;
ok ( fbdi - > FileNameLength = = sizeof ( WCHAR ) , " wrong length %x \n " , fbdi - > FileNameLength ) ;
ok ( fbdi - > FileName [ 0 ] = = ' . ' , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( fbdi - > FileName , fbdi - > FileNameLength / sizeof ( WCHAR ) ) ) ;
next = ( FILE_BOTH_DIRECTORY_INFORMATION * ) ( data + fbdi - > NextEntryOffset ) ;
ok ( next - > NextEntryOffset = = ( ( offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 2 ] ) + 7 ) & ~ 7 ) ,
" wrong offset %x \n " , next - > NextEntryOffset ) ;
ok ( next - > FileNameLength = = 2 * sizeof ( WCHAR ) , " wrong length %x \n " , next - > FileNameLength ) ;
filename = next - > FileName ;
ok ( filename [ 0 ] = = ' . ' & & filename [ 1 ] = = ' . ' , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( next - > FileName , next - > FileNameLength / sizeof ( WCHAR ) ) ) ;
2019-03-01 21:08:19 +01:00
data_size = fbdi - > NextEntryOffset + offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) ;
2016-04-28 09:44:25 +02:00
memset ( data , 0x55 , data_size ) ;
U ( io ) . Status = 0xdeadbeef ;
U ( io ) . Information = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , FALSE , NULL , TRUE ) ;
ok ( status = = STATUS_SUCCESS , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_SUCCESS , " wrong status %x \n " , U ( io ) . Status ) ;
ok ( U ( io ) . Information = = offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) ,
" wrong info %lx \n " , U ( io ) . Information ) ;
ok ( fbdi - > NextEntryOffset = = 0 , " wrong offset %x \n " , fbdi - > NextEntryOffset ) ;
ok ( fbdi - > FileNameLength = = sizeof ( WCHAR ) , " wrong length %x \n " , fbdi - > FileNameLength ) ;
ok ( fbdi - > FileName [ 0 ] = = ' . ' , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( fbdi - > FileName , fbdi - > FileNameLength / sizeof ( WCHAR ) ) ) ;
next = ( FILE_BOTH_DIRECTORY_INFORMATION * ) & fbdi - > FileName [ 1 ] ;
ok ( next - > NextEntryOffset = = 0x55555555 , " wrong offset %x \n " , next - > NextEntryOffset ) ;
2019-03-01 21:08:19 +01:00
data_size = fbdi - > NextEntryOffset + offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 2 ] ) ;
2016-04-28 09:44:25 +02:00
memset ( data , 0x55 , data_size ) ;
U ( io ) . Status = 0xdeadbeef ;
U ( io ) . Information = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , FALSE , NULL , TRUE ) ;
ok ( status = = STATUS_SUCCESS , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_SUCCESS , " wrong status %x \n " , U ( io ) . Status ) ;
ok ( U ( io ) . Information = = offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) ,
" wrong info %lx \n " , U ( io ) . Information ) ;
ok ( fbdi - > NextEntryOffset = = 0 , " wrong offset %x \n " , fbdi - > NextEntryOffset ) ;
data_size = ( ( offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) +
offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 2 ] ) ;
memset ( data , 0x55 , data_size ) ;
U ( io ) . Status = 0xdeadbeef ;
U ( io ) . Information = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , FALSE , NULL , TRUE ) ;
ok ( status = = STATUS_SUCCESS , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_SUCCESS , " wrong status %x \n " , U ( io ) . Status ) ;
ok ( U ( io ) . Information = = data_size , " wrong info %lx / %x \n " , U ( io ) . Information , data_size ) ;
ok ( fbdi - > NextEntryOffset = = ( ( offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" wrong offset %x \n " , fbdi - > NextEntryOffset ) ;
ok ( fbdi - > FileNameLength = = sizeof ( WCHAR ) , " wrong length %x \n " , fbdi - > FileNameLength ) ;
ok ( fbdi - > FileName [ 0 ] = = ' . ' , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( fbdi - > FileName , fbdi - > FileNameLength / sizeof ( WCHAR ) ) ) ;
next = ( FILE_BOTH_DIRECTORY_INFORMATION * ) ( data + fbdi - > NextEntryOffset ) ;
ok ( next - > NextEntryOffset = = 0 , " wrong offset %x \n " , next - > NextEntryOffset ) ;
ok ( next - > FileNameLength = = 2 * sizeof ( WCHAR ) , " wrong length %x \n " , next - > FileNameLength ) ;
filename = next - > FileName ;
ok ( filename [ 0 ] = = ' . ' & & filename [ 1 ] = = ' . ' , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( next - > FileName , next - > FileNameLength / sizeof ( WCHAR ) ) ) ;
2016-05-04 09:05:35 +02:00
data_size = ( ( offsetof ( FILE_NAMES_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) +
offsetof ( FILE_NAMES_INFORMATION , FileName [ 2 ] ) ;
memset ( data , 0x55 , data_size ) ;
U ( io ) . Status = 0xdeadbeef ;
U ( io ) . Information = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileNamesInformation , FALSE , NULL , TRUE ) ;
ok ( status = = STATUS_SUCCESS , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_SUCCESS , " wrong status %x \n " , U ( io ) . Status ) ;
ok ( U ( io ) . Information = = data_size , " wrong info %lx / %x \n " , U ( io ) . Information , data_size ) ;
names = ( FILE_NAMES_INFORMATION * ) data ;
ok ( names - > NextEntryOffset = = ( ( offsetof ( FILE_NAMES_INFORMATION , FileName [ 1 ] ) + 7 ) & ~ 7 ) ,
" wrong offset %x \n " , names - > NextEntryOffset ) ;
ok ( names - > FileNameLength = = sizeof ( WCHAR ) , " wrong length %x \n " , names - > FileNameLength ) ;
ok ( names - > FileName [ 0 ] = = ' . ' , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( names - > FileName , names - > FileNameLength / sizeof ( WCHAR ) ) ) ;
names = ( FILE_NAMES_INFORMATION * ) ( data + names - > NextEntryOffset ) ;
ok ( names - > NextEntryOffset = = 0 , " wrong offset %x \n " , names - > NextEntryOffset ) ;
ok ( names - > FileNameLength = = 2 * sizeof ( WCHAR ) , " wrong length %x \n " , names - > FileNameLength ) ;
filename = names - > FileName ;
ok ( filename [ 0 ] = = ' . ' & & filename [ 1 ] = = ' . ' , " incorrect long file name: %s \n " ,
wine_dbgstr_wn ( names - > FileName , names - > FileNameLength / sizeof ( WCHAR ) ) ) ;
2015-12-21 18:42:04 +01:00
pNtClose ( dirh ) ;
2016-05-02 09:29:19 +02:00
/* create new handle to change mask */
status = pNtOpenFile ( & dirh , SYNCHRONIZE | FILE_LIST_DIRECTORY , & attr , & io , FILE_SHARE_READ ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE ) ;
ok ( status = = STATUS_SUCCESS , " failed to open dir '%s' \n " , testdirA ) ;
pRtlInitUnicodeString ( & mask , dummyW ) ;
U ( io ) . Status = 0xdeadbeef ;
2016-05-04 09:05:35 +02:00
data_size = sizeof ( data ) ;
2016-05-02 09:29:19 +02:00
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , & mask , TRUE ) ;
ok ( status = = STATUS_NO_SUCH_FILE , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = 0xdeadbeef , " wrong status %x \n " , U ( io ) . Status ) ;
U ( io ) . Status = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , NULL , FALSE ) ;
ok ( status = = STATUS_NO_MORE_FILES , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_NO_MORE_FILES , " wrong status %x \n " , U ( io ) . Status ) ;
U ( io ) . Status = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , NULL , TRUE ) ;
ok ( status = = STATUS_NO_MORE_FILES , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = STATUS_NO_MORE_FILES , " wrong status %x \n " , U ( io ) . Status ) ;
pNtClose ( dirh ) ;
2016-04-28 09:44:25 +02:00
U ( io ) . Status = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( ( HANDLE ) 0xbeef , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , NULL , TRUE ) ;
ok ( status = = STATUS_INVALID_HANDLE , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = 0xdeadbeef , " wrong status %x \n " , U ( io ) . Status ) ;
2020-06-12 14:20:16 +02:00
GetModuleFileNameA ( 0 , buffer , sizeof ( buffer ) ) ;
h = CreateFileA ( buffer , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , 0 , 0 ) ;
if ( h ! = INVALID_HANDLE_VALUE )
{
U ( io ) . Status = 0xdeadbeef ;
status = pNtQueryDirectoryFile ( h , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , NULL , TRUE ) ;
ok ( status = = STATUS_INVALID_PARAMETER , " wrong status %x \n " , status ) ;
ok ( U ( io ) . Status = = 0xdeadbeef , " wrong status %x \n " , U ( io ) . Status ) ;
CloseHandle ( h ) ;
}
2009-09-24 18:49:46 +02:00
done :
2016-05-03 06:16:16 +02:00
test_directory_sort ( testdirW ) ;
2016-05-03 06:01:29 +02:00
tear_down_attribute_test ( testdirW ) ;
2009-12-07 10:32:03 +01:00
pRtlFreeUnicodeString ( & ntdirname ) ;
2009-09-24 18:49:46 +02:00
}
2015-05-19 23:32:35 +02:00
static void set_up_case_test ( const char * testdir )
{
BOOL ret ;
2020-02-11 19:09:35 +01:00
char buf [ MAX_PATH + 5 ] ;
2015-05-19 23:32:35 +02:00
HANDLE h ;
ret = CreateDirectoryA ( testdir , NULL ) ;
ok ( ret , " couldn't create dir '%s', error %d \n " , testdir , GetLastError ( ) ) ;
sprintf ( buf , " %s \\ %s " , testdir , " TesT " ) ;
h = CreateFileA ( buf , GENERIC_READ | GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS ,
FILE_ATTRIBUTE_NORMAL , 0 ) ;
ok ( h ! = INVALID_HANDLE_VALUE , " failed to create temp file '%s' \n " , buf ) ;
CloseHandle ( h ) ;
}
static void tear_down_case_test ( const char * testdir )
{
int ret ;
char buf [ MAX_PATH ] ;
sprintf ( buf , " %s \\ %s " , testdir , " TesT " ) ;
ret = DeleteFileA ( buf ) ;
ok ( ret | | ( GetLastError ( ) = = ERROR_PATH_NOT_FOUND ) ,
" Failed to rm %s, error %d \n " , buf , GetLastError ( ) ) ;
RemoveDirectoryA ( testdir ) ;
}
static void test_NtQueryDirectoryFile_case ( void )
{
static const char testfile [ ] = " TesT " ;
static const WCHAR testfile_w [ ] = { ' T ' , ' e ' , ' s ' , ' T ' } ;
static int testfile_len = sizeof ( testfile ) - 1 ;
static WCHAR testmask [ ] = { ' t ' , ' e ' , ' s ' , ' t ' } ;
OBJECT_ATTRIBUTES attr ;
UNICODE_STRING ntdirname ;
char testdir [ MAX_PATH ] ;
WCHAR testdir_w [ MAX_PATH ] ;
HANDLE dirh ;
UNICODE_STRING mask ;
IO_STATUS_BLOCK io ;
UINT data_size , data_len ;
BYTE data [ 8192 ] ;
FILE_BOTH_DIRECTORY_INFORMATION * dir_info = ( FILE_BOTH_DIRECTORY_INFORMATION * ) data ;
DWORD status ;
WCHAR * name ;
ULONG name_len ;
/* Clean up from prior aborted run, if any, then set up test files */
ok ( GetTempPathA ( MAX_PATH , testdir ) , " couldn't get temp dir \n " ) ;
strcat ( testdir , " case.tmp " ) ;
tear_down_case_test ( testdir ) ;
set_up_case_test ( testdir ) ;
pRtlMultiByteToUnicodeN ( testdir_w , sizeof ( testdir_w ) , NULL , testdir , strlen ( testdir ) + 1 ) ;
if ( ! pRtlDosPathNameToNtPathName_U ( testdir_w , & ntdirname , NULL , NULL ) )
{
ok ( 0 , " RtlDosPathNametoNtPathName_U failed \n " ) ;
goto done ;
}
InitializeObjectAttributes ( & attr , & ntdirname , OBJ_CASE_INSENSITIVE , 0 , NULL ) ;
data_size = offsetof ( FILE_BOTH_DIRECTORY_INFORMATION , FileName [ 256 ] ) ;
status = pNtOpenFile ( & dirh , SYNCHRONIZE | FILE_LIST_DIRECTORY , & attr , & io , FILE_SHARE_READ ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE ) ;
ok ( status = = STATUS_SUCCESS , " failed to open dir '%s', ret 0x%x, error %d \n " , testdir , status , GetLastError ( ) ) ;
if ( status ! = STATUS_SUCCESS )
{
skip ( " can't test if we can't open the directory \n " ) ;
return ;
}
mask . Buffer = testmask ;
2015-06-04 16:12:58 +02:00
mask . Length = mask . MaximumLength = sizeof ( testmask ) ;
2015-05-19 23:32:35 +02:00
pNtQueryDirectoryFile ( dirh , NULL , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , TRUE , & mask , FALSE ) ;
ok ( U ( io ) . Status = = STATUS_SUCCESS , " failed to query directory; status %x \n " , U ( io ) . Status ) ;
data_len = io . Information ;
ok ( data_len > = sizeof ( FILE_BOTH_DIRECTORY_INFORMATION ) , " not enough data in directory \n " ) ;
name = dir_info - > FileName ;
name_len = dir_info - > FileNameLength / sizeof ( WCHAR ) ;
ok ( name_len = = testfile_len , " unexpected filename length %u \n " , name_len ) ;
ok ( ! memcmp ( name , testfile_w , testfile_len * sizeof ( WCHAR ) ) , " unexpected filename %s \n " ,
wine_dbgstr_wn ( name , name_len ) ) ;
pNtClose ( dirh ) ;
done :
tear_down_case_test ( testdir ) ;
pRtlFreeUnicodeString ( & ntdirname ) ;
}
2009-10-28 10:54:22 +01:00
static void test_redirection ( void )
{
ULONG old , cur ;
NTSTATUS status ;
2020-07-24 13:29:31 +02:00
ULONGLONG * tls64 = NULL ;
2009-10-28 10:54:22 +01:00
if ( ! pRtlWow64EnableFsRedirection | | ! pRtlWow64EnableFsRedirectionEx )
{
skip ( " Wow64 redirection not supported \n " ) ;
return ;
}
status = pRtlWow64EnableFsRedirectionEx ( FALSE , & old ) ;
if ( status = = STATUS_NOT_IMPLEMENTED )
{
skip ( " Wow64 redirection not supported \n " ) ;
return ;
}
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
2020-07-24 13:29:31 +02:00
# ifndef _WIN64
if ( NtCurrentTeb ( ) - > GdiBatchCount )
tls64 = ( ( TEB64 * ) NtCurrentTeb ( ) - > GdiBatchCount ) - > TlsSlots + WOW64_TLS_FILESYSREDIR ;
# endif
2009-10-28 10:54:22 +01:00
status = pRtlWow64EnableFsRedirectionEx ( FALSE , & cur ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
ok ( ! cur , " RtlWow64EnableFsRedirectionEx got %u \n " , cur ) ;
2020-07-24 13:29:31 +02:00
if ( tls64 ) ok ( * tls64 = = FALSE , " wrong tls %s \n " , wine_dbgstr_longlong ( * tls64 ) ) ;
2009-10-28 10:54:22 +01:00
status = pRtlWow64EnableFsRedirectionEx ( TRUE , & cur ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
status = pRtlWow64EnableFsRedirectionEx ( TRUE , & cur ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
ok ( cur = = 1 , " RtlWow64EnableFsRedirectionEx got %u \n " , cur ) ;
2020-07-24 13:29:31 +02:00
if ( tls64 ) ok ( * tls64 = = TRUE , " wrong tls %s \n " , wine_dbgstr_longlong ( * tls64 ) ) ;
2009-10-28 10:54:22 +01:00
status = pRtlWow64EnableFsRedirection ( TRUE ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
status = pRtlWow64EnableFsRedirectionEx ( TRUE , & cur ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
ok ( ! cur , " RtlWow64EnableFsRedirectionEx got %u \n " , cur ) ;
2020-07-24 13:29:31 +02:00
if ( tls64 ) ok ( * tls64 = = TRUE , " wrong tls %s \n " , wine_dbgstr_longlong ( * tls64 ) ) ;
status = pRtlWow64EnableFsRedirectionEx ( 123 , & cur ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
ok ( cur = = TRUE , " RtlWow64EnableFsRedirectionEx got %u \n " , cur ) ;
if ( tls64 ) ok ( * tls64 = = 123 , " wrong tls %s \n " , wine_dbgstr_longlong ( * tls64 ) ) ;
status = pRtlWow64EnableFsRedirectionEx ( 0xdeadbeef , & cur ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
ok ( cur = = 123 , " RtlWow64EnableFsRedirectionEx got %u \n " , cur ) ;
if ( tls64 ) ok ( * tls64 = = 0xdeadbeef , " wrong tls %s \n " , wine_dbgstr_longlong ( * tls64 ) ) ;
2009-10-28 10:54:22 +01:00
2012-08-21 21:58:17 +02:00
status = pRtlWow64EnableFsRedirectionEx ( TRUE , NULL ) ;
ok ( status = = STATUS_ACCESS_VIOLATION , " RtlWow64EnableFsRedirectionEx failed with status %x \n " , status ) ;
status = pRtlWow64EnableFsRedirectionEx ( TRUE , ( void * ) 1 ) ;
2016-08-07 00:00:21 +02:00
ok ( status = = STATUS_ACCESS_VIOLATION , " RtlWow64EnableFsRedirectionEx failed with status %x \n " , status ) ;
status = pRtlWow64EnableFsRedirectionEx ( TRUE , ( void * ) 0xDEADBEEF ) ;
2012-08-21 21:58:17 +02:00
ok ( status = = STATUS_ACCESS_VIOLATION , " RtlWow64EnableFsRedirectionEx failed with status %x \n " , status ) ;
2009-10-28 10:54:22 +01:00
status = pRtlWow64EnableFsRedirection ( FALSE ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
status = pRtlWow64EnableFsRedirectionEx ( FALSE , & cur ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
ok ( cur = = 1 , " RtlWow64EnableFsRedirectionEx got %u \n " , cur ) ;
2020-07-24 13:29:31 +02:00
if ( tls64 ) ok ( * tls64 = = FALSE , " wrong tls %s \n " , wine_dbgstr_longlong ( * tls64 ) ) ;
2009-10-28 10:54:22 +01:00
pRtlWow64EnableFsRedirectionEx ( old , & cur ) ;
}
2009-09-24 18:49:46 +02:00
START_TEST ( directory )
{
2016-05-03 06:16:16 +02:00
WCHAR sysdir [ MAX_PATH ] ;
2009-09-24 18:49:46 +02:00
HMODULE hntdll = GetModuleHandleA ( " ntdll.dll " ) ;
if ( ! hntdll )
{
skip ( " not running on NT, skipping test \n " ) ;
return ;
}
pNtClose = ( void * ) GetProcAddress ( hntdll , " NtClose " ) ;
pNtOpenFile = ( void * ) GetProcAddress ( hntdll , " NtOpenFile " ) ;
pNtQueryDirectoryFile = ( void * ) GetProcAddress ( hntdll , " NtQueryDirectoryFile " ) ;
2016-05-03 06:15:40 +02:00
pNtQueryInformationFile = ( void * ) GetProcAddress ( hntdll , " NtQueryInformationFile " ) ;
pNtSetInformationFile = ( void * ) GetProcAddress ( hntdll , " NtSetInformationFile " ) ;
2009-09-24 18:49:46 +02:00
pRtlCreateUnicodeStringFromAsciiz = ( void * ) GetProcAddress ( hntdll , " RtlCreateUnicodeStringFromAsciiz " ) ;
pRtlDosPathNameToNtPathName_U = ( void * ) GetProcAddress ( hntdll , " RtlDosPathNameToNtPathName_U " ) ;
pRtlInitUnicodeString = ( void * ) GetProcAddress ( hntdll , " RtlInitUnicodeString " ) ;
2009-12-07 10:32:03 +01:00
pRtlFreeUnicodeString = ( void * ) GetProcAddress ( hntdll , " RtlFreeUnicodeString " ) ;
2016-05-03 06:16:16 +02:00
pRtlCompareUnicodeString = ( void * ) GetProcAddress ( hntdll , " RtlCompareUnicodeString " ) ;
2009-09-24 18:49:46 +02:00
pRtlMultiByteToUnicodeN = ( void * ) GetProcAddress ( hntdll , " RtlMultiByteToUnicodeN " ) ;
2009-10-28 10:54:22 +01:00
pRtlWow64EnableFsRedirection = ( void * ) GetProcAddress ( hntdll , " RtlWow64EnableFsRedirection " ) ;
pRtlWow64EnableFsRedirectionEx = ( void * ) GetProcAddress ( hntdll , " RtlWow64EnableFsRedirectionEx " ) ;
2009-09-24 18:49:46 +02:00
2016-05-03 06:16:16 +02:00
GetSystemDirectoryW ( sysdir , MAX_PATH ) ;
test_directory_sort ( sysdir ) ;
2009-09-24 18:49:46 +02:00
test_NtQueryDirectoryFile ( ) ;
2015-05-19 23:32:35 +02:00
test_NtQueryDirectoryFile_case ( ) ;
2009-10-28 10:54:22 +01:00
test_redirection ( ) ;
2009-09-24 18:49:46 +02:00
}