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"
# 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 ) ;
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 ) ;
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 */
const char * name ; /* filename to use */
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) */
WCHAR nameW [ 20 ] ; /* unicode version of name (filled in later) */
} testfiles [ ] = {
2011-08-04 22:24:48 +02:00
{ 0 , 0 , FILE_ATTRIBUTE_NORMAL , " n.tmp " , NULL , " normal " } ,
{ 1 , 0 , FILE_ATTRIBUTE_HIDDEN , " h.tmp " , NULL , " hidden " } ,
{ 1 , 0 , FILE_ATTRIBUTE_SYSTEM , " s.tmp " , NULL , " system " } ,
{ 0 , 0 , FILE_ATTRIBUTE_DIRECTORY , " d.tmp " , NULL , " directory " } ,
{ 0 , 0 , FILE_ATTRIBUTE_DIRECTORY , " . " , NULL , " . directory " } ,
{ 0 , 0 , FILE_ATTRIBUTE_DIRECTORY , " .. " , NULL , " .. directory " } ,
{ 0 , 0 , 0 , NULL }
2009-09-29 17:56:20 +02:00
} ;
static const int max_test_dir_size = 20 ; /* size of above plus some for .. etc */
/* Create a test directory full of attribute test files, clear counts */
static void set_up_attribute_test ( const char * testdirA )
{
int i ;
2010-12-28 21:10:40 +01:00
BOOL ret ;
2009-09-29 17:56:20 +02:00
2010-12-28 21:10:40 +01:00
ret = CreateDirectoryA ( testdirA , NULL ) ;
ok ( ret , " couldn't create dir '%s', error %d \n " , testdirA , GetLastError ( ) ) ;
2009-09-29 17:56:20 +02:00
for ( i = 0 ; testfiles [ i ] . name ; i + + ) {
char buf [ MAX_PATH ] ;
pRtlMultiByteToUnicodeN ( testfiles [ i ] . nameW , sizeof ( testfiles [ i ] . nameW ) , NULL , testfiles [ i ] . name , strlen ( testfiles [ i ] . name ) + 1 ) ;
2011-07-17 01:48:15 +02:00
if ( strcmp ( testfiles [ i ] . name , " . " ) = = 0 | | strcmp ( testfiles [ i ] . name , " .. " ) = = 0 )
continue ;
sprintf ( buf , " %s \\ %s " , testdirA , testfiles [ i ] . name ) ;
2009-09-29 17:56:20 +02:00
if ( testfiles [ i ] . attr & FILE_ATTRIBUTE_DIRECTORY ) {
2010-12-28 21:10:40 +01:00
ret = CreateDirectoryA ( buf , NULL ) ;
ok ( ret , " couldn't create dir '%s', error %d \n " , buf , GetLastError ( ) ) ;
2009-09-29 17:56:20 +02:00
} else {
HANDLE h = CreateFileA ( buf ,
GENERIC_READ | GENERIC_WRITE ,
0 , NULL , CREATE_ALWAYS ,
testfiles [ i ] . attr , 0 ) ;
ok ( h ! = INVALID_HANDLE_VALUE , " failed to create temp file '%s' \n " , buf ) ;
CloseHandle ( h ) ;
}
}
}
2011-08-04 22:24:48 +02:00
static void reset_found_files ( void )
{
int i ;
for ( i = 0 ; testfiles [ i ] . name ; i + + )
testfiles [ i ] . nfound = 0 ;
}
2009-09-29 17:56:20 +02:00
/* Remove the given test directory and the attribute test files, if any */
static void tear_down_attribute_test ( const char * testdirA )
{
int i ;
for ( i = 0 ; testfiles [ i ] . name ; i + + ) {
int ret ;
char buf [ MAX_PATH ] ;
2011-07-17 01:48:15 +02:00
if ( strcmp ( testfiles [ i ] . name , " . " ) = = 0 | | strcmp ( testfiles [ i ] . name , " .. " ) = = 0 )
continue ;
2009-09-29 17:56:20 +02:00
sprintf ( buf , " %s \\ %s " , testdirA , testfiles [ i ] . name ) ;
if ( testfiles [ i ] . attr & FILE_ATTRIBUTE_DIRECTORY ) {
ret = RemoveDirectory ( buf ) ;
ok ( ret | | ( GetLastError ( ) = = ERROR_PATH_NOT_FOUND ) ,
" Failed to rmdir %s, error %d \n " , buf , GetLastError ( ) ) ;
} else {
ret = DeleteFile ( buf ) ;
ok ( ret | | ( GetLastError ( ) = = ERROR_PATH_NOT_FOUND ) ,
" Failed to rm %s, error %d \n " , buf , GetLastError ( ) ) ;
}
}
RemoveDirectoryA ( testdirA ) ;
}
/* 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 ) ;
for ( i = 0 ; testfiles [ i ] . name ; i + + ) {
int len = strlen ( testfiles [ i ] . name ) ;
if ( namelen ! = len | | memcmp ( nameW , testfiles [ i ] . nameW , len * sizeof ( WCHAR ) ) )
continue ;
2011-08-04 22:24:48 +02:00
if ( ! testfiles [ i ] . attr_done ) {
if ( testfiles [ i ] . todo ) {
todo_wine
ok ( attrib = = ( testfiles [ i ] . attr & attribmask ) , " file %s: expected %s (%x), got %x (is your linux new enough?) \n " , testfiles [ i ] . name , testfiles [ i ] . description , testfiles [ i ] . attr , attrib ) ;
} else {
ok ( attrib = = ( testfiles [ i ] . attr & attribmask ) , " file %s: expected %s (%x), got %x (is your linux new enough?) \n " , testfiles [ i ] . name , testfiles [ i ] . description , testfiles [ i ] . attr , attrib ) ;
}
testfiles [ i ] . attr_done = TRUE ;
2009-09-29 17:56:20 +02:00
}
testfiles [ i ] . nfound + + ;
break ;
}
ok ( testfiles [ i ] . name ! = NULL , " unexpected file found \n " ) ;
}
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
{
HANDLE dirh ;
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 ;
DWORD status ;
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 ( ) ;
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 */
2011-08-04 22:24:48 +02:00
status = pNtOpenFile ( & dirh , SYNCHRONIZE | FILE_LIST_DIRECTORY , attr , & io , FILE_OPEN ,
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
}
2013-07-01 19:50:43 +02:00
pNtQueryDirectoryFile ( dirh , NULL , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , single_entry , mask , restart_flag ) ;
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 " ) ;
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 ) {
2013-07-01 19:50:43 +02:00
pNtQueryDirectoryFile ( dirh , 0 , NULL , NULL , & io , data , data_size ,
FileBothDirectoryInformation , single_entry , mask , FALSE ) ;
2009-10-17 20:28:14 +02:00
if ( U ( io ) . Status = = STATUS_NO_MORE_FILES )
2009-09-24 18:49:46 +02:00
break ;
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 ;
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 )
for ( i = 0 ; testfiles [ i ] . name ; i + + )
ok ( testfiles [ i ] . nfound = = ( testfiles [ i ] . nameW = = mask - > Buffer ) ,
" 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
for ( i = 0 ; testfiles [ i ] . name ; i + + )
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 ) ;
2009-09-24 18:49:46 +02:00
pNtClose ( dirh ) ;
2011-08-04 22:24:48 +02:00
}
static void test_NtQueryDirectoryFile ( void )
{
OBJECT_ATTRIBUTES attr ;
UNICODE_STRING ntdirname ;
char testdirA [ MAX_PATH ] ;
WCHAR testdirW [ MAX_PATH ] ;
2013-07-01 19:50:43 +02:00
int i ;
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 " ) ;
tear_down_attribute_test ( testdirA ) ;
set_up_attribute_test ( testdirA ) ;
pRtlMultiByteToUnicodeN ( testdirW , sizeof ( testdirW ) , NULL , testdirA , strlen ( testdirA ) + 1 ) ;
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 ) ;
for ( i = 0 ; testfiles [ i ] . name ; i + + )
{
UNICODE_STRING mask ;
2013-07-02 10:03:50 +02:00
if ( testfiles [ i ] . nameW [ 0 ] = = ' . ' ) continue ; /* . and .. as masks are broken on Windows */
2013-07-01 19:50:43 +02:00
mask . Buffer = testfiles [ i ] . nameW ;
mask . Length = mask . MaximumLength = lstrlenW ( testfiles [ i ] . nameW ) * sizeof ( WCHAR ) ;
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
2009-09-24 18:49:46 +02:00
done :
2009-09-29 17:56:20 +02:00
tear_down_attribute_test ( testdirA ) ;
2009-12-07 10:32:03 +01:00
pRtlFreeUnicodeString ( & ntdirname ) ;
2009-09-24 18:49:46 +02:00
}
2009-10-28 10:54:22 +01:00
static void test_redirection ( void )
{
ULONG old , cur ;
NTSTATUS status ;
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 ) ;
status = pRtlWow64EnableFsRedirectionEx ( FALSE , & cur ) ;
ok ( ! status , " RtlWow64EnableFsRedirectionEx failed status %x \n " , status ) ;
ok ( ! cur , " RtlWow64EnableFsRedirectionEx got %u \n " , cur ) ;
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 ) ;
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 ) ;
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 ) ;
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 ) ;
pRtlWow64EnableFsRedirectionEx ( old , & cur ) ;
}
2009-09-24 18:49:46 +02:00
START_TEST ( directory )
{
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 " ) ;
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 " ) ;
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
test_NtQueryDirectoryFile ( ) ;
2009-10-28 10:54:22 +01:00
test_redirection ( ) ;
2009-09-24 18:49:46 +02:00
}