Sebastian Lackner : kernel32/tests: Add tests for deleting readonly files with NtCreateFile.
Alexandre Julliard
julliard at wine.codeweavers.com
Thu Apr 30 07:19:30 CDT 2015
Module: wine
Branch: master
Commit: 10ee3f44b1119c7b7e1d4684e691a6cea5713ea2
URL: http://source.winehq.org/git/wine.git/?a=commit;h=10ee3f44b1119c7b7e1d4684e691a6cea5713ea2
Author: Sebastian Lackner <sebastian at fds-team.de>
Date: Fri Apr 17 11:22:51 2015 +0200
kernel32/tests: Add tests for deleting readonly files with NtCreateFile.
Wine currently implements DeleteFile based on NtCreateFile with access mask
GENERIC_READ | GENERIC_WRITE | DELETE, but this is wrong. This test shows that
NtCreateFile with FILE_DELETE_ON_CLOSE should also fail without explicitly
requesting read/write access.
---
dlls/kernel32/tests/file.c | 77 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 99fffab..9a6e972 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -28,10 +28,13 @@
#include <time.h>
#include <stdio.h>
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
#include "wine/test.h"
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
+#include "winternl.h"
#include "winnls.h"
#include "fileapi.h"
@@ -48,6 +51,10 @@ static HRESULT (WINAPI *pCopyFile2)(PCWSTR,PCWSTR,COPYFILE2_EXTENDED_PARAMETERS*
static HANDLE (WINAPI *pCreateFile2)(LPCWSTR, DWORD, DWORD, DWORD, CREATEFILE2_EXTENDED_PARAMETERS*);
static DWORD (WINAPI *pGetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD, DWORD);
static DWORD (WINAPI *pGetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, DWORD);
+static NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
+ PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
+static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR*);
+static NTSTATUS (WINAPI *pRtlAnsiStringToUnicodeString)(PUNICODE_STRING, PCANSI_STRING, BOOLEAN);
static const char filename[] = "testfile.xxx";
static const char sillytext[] =
@@ -72,8 +79,13 @@ struct test_list {
static void InitFunctionPointers(void)
{
+ HMODULE hntdll = GetModuleHandleA("ntdll");
HMODULE hkernel32 = GetModuleHandleA("kernel32");
+ pNtCreateFile = (void *)GetProcAddress(hntdll, "NtCreateFile");
+ pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U");
+ pRtlAnsiStringToUnicodeString = (void *)GetProcAddress(hntdll, "RtlAnsiStringToUnicodeString");
+
pFindFirstFileExA=(void*)GetProcAddress(hkernel32, "FindFirstFileExA");
pReplaceFileA=(void*)GetProcAddress(hkernel32, "ReplaceFileA");
pReplaceFileW=(void*)GetProcAddress(hkernel32, "ReplaceFileW");
@@ -243,15 +255,36 @@ static void test__lclose( void )
ok( ret != 0, "DeleteFile failed (%d)\n", GetLastError( ) );
}
+/* helper function for test__lcreat */
+static void get_nt_pathW( const char *name, UNICODE_STRING *nameW )
+{
+ UNICODE_STRING strW;
+ ANSI_STRING str;
+ NTSTATUS status;
+ BOOLEAN ret;
+ RtlInitAnsiString( &str, name );
+
+ status = pRtlAnsiStringToUnicodeString( &strW, &str, TRUE );
+ ok( !status, "RtlAnsiStringToUnicodeString failed with %08x\n", status );
+
+ ret = pRtlDosPathNameToNtPathName_U( strW.Buffer, nameW, NULL, NULL );
+ ok( ret, "RtlDosPathNameToNtPathName_U failed\n" );
+
+ RtlFreeUnicodeString( &strW );
+}
static void test__lcreat( void )
{
+ UNICODE_STRING filenameW;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
HFILE filehandle;
char buffer[10000];
WIN32_FIND_DATAA search_results;
char slashname[] = "testfi/";
int err;
- HANDLE find;
+ HANDLE find, file;
+ NTSTATUS status;
BOOL ret;
filehandle = _lcreat( filename, 0 );
@@ -287,12 +320,54 @@ static void test__lcreat( void )
ok( INVALID_HANDLE_VALUE != find, "should be able to find file\n" );
FindClose( find );
+ SetLastError( 0xdeadbeef );
ok( 0 == DeleteFileA( filename ), "shouldn't be able to delete a readonly file\n" );
+ ok( GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError() );
ok( SetFileAttributesA(filename, FILE_ATTRIBUTE_NORMAL ) != 0, "couldn't change attributes on file\n" );
ok( DeleteFileA( filename ) != 0, "now it should be possible to delete the file!\n" );
+ filehandle = _lcreat( filename, 1 ); /* readonly */
+ ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%d)\n", filename, GetLastError() );
+ ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen(sillytext) ),
+ "_hwrite shouldn't be able to write never the less\n" );
+ ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" );
+
+ find = FindFirstFileA( filename, &search_results );
+ ok( INVALID_HANDLE_VALUE != find, "should be able to find file\n" );
+ FindClose( find );
+
+ get_nt_pathW( filename, &filenameW );
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.ObjectName = &filenameW;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ status = NtCreateFile( &file, GENERIC_READ | GENERIC_WRITE | DELETE, &attr, &io, NULL, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0 );
+ ok( status == STATUS_ACCESS_DENIED, "expected STATUS_ACCESS_DENIED, got %08x\n", status );
+ ok( GetFileAttributesA( filename ) != INVALID_FILE_ATTRIBUTES, "file was deleted\n" );
+
+ status = NtCreateFile( &file, DELETE, &attr, &io, NULL, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0 );
+ todo_wine
+ ok( status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08x\n", status );
+ if (!status) CloseHandle( file );
+
+ RtlFreeUnicodeString( &filenameW );
+
+ todo_wine
+ ok( GetFileAttributesA( filename ) != INVALID_FILE_ATTRIBUTES, "file was deleted\n" );
+ todo_wine
+ ok( SetFileAttributesA(filename, FILE_ATTRIBUTE_NORMAL ) != 0, "couldn't change attributes on file\n" );
+ todo_wine
+ ok( DeleteFileA( filename ) != 0, "now it should be possible to delete the file\n" );
+
filehandle = _lcreat( filename, 2 );
ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%d)\n", filename, GetLastError( ) );
More information about the wine-cvs
mailing list