#define WIN32_NO_STATUS
#include "wine/test.h"
-#include "winternl.h"
+#include "wine/winternl.h"
#include "winuser.h"
#include "wine/winioctl.h"
+/* FIXME */
+typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ _ANONYMOUS_UNION union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ } DUMMYUNIONNAME;
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
#ifndef IO_COMPLETION_ALL_ACCESS
#define IO_COMPLETION_ALL_ACCESS 0x001F0003
#endif
static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,
PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN);
static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FS_INFORMATION_CLASS);
+static NTSTATUS (WINAPI *pNtQueryFullAttributesFile)(const OBJECT_ATTRIBUTES*, FILE_NETWORK_OPEN_INFORMATION*);
+static NTSTATUS (WINAPI *pNtQueryEaFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,BOOLEAN,PVOID,ULONG,PULONG,BOOLEAN);
static inline BOOL is_signaled( HANDLE obj )
{
return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0;
}
+static const char* debugstr_longlong(ULONGLONG ll)
+{
+ static char str[17];
+ if (sizeof(ll) > sizeof(unsigned long) && ll >> 32)
+ sprintf(str, "%lx%08lx", (unsigned long)(ll >> 32), (unsigned long)ll);
+ else
+ sprintf(str, "%lx", (unsigned long)ll);
+ return str;
+}
+
#define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c"
#define TEST_BUF_LEN 3
'\\','f','a','i','l','i','n','g',0};
static const WCHAR questionmarkInvalidNameW[] = {'a','f','i','l','e','?',0};
static const WCHAR pipeInvalidNameW[] = {'a','|','b',0};
+ static const WCHAR pathInvalidNtW[] = {'\\','\\','?','\\',0};
+ static const WCHAR pathInvalidNt2W[] = {'\\','?','?','\\',0};
+ static const WCHAR pathInvalidDosW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
+ static const char testdata[] = "Hello World";
+ FILE_NETWORK_OPEN_INFORMATION info;
NTSTATUS status;
HANDLE dir, file;
WCHAR path[MAX_PATH];
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
UNICODE_STRING nameW;
+ LARGE_INTEGER offset;
+ char buf[32];
+ DWORD ret;
GetCurrentDirectoryW( MAX_PATH, path );
pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL );
attr.SecurityQualityOfService = NULL;
/* try various open modes and options on directories */
- status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
- FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 );
+ status = pNtCreateFile( &dir, GENERIC_READ|GENERIC_WRITE, &attr, &io, NULL, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 );
ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+
+ U(io).Status = 0xdeadbeef;
+ offset.QuadPart = 0;
+ status = pNtReadFile( dir, NULL, NULL, NULL, &io, buf, sizeof(buf), &offset, NULL );
+ ok( status == STATUS_INVALID_DEVICE_REQUEST || status == STATUS_PENDING, "NtReadFile error %08x\n", status );
+ if (status == STATUS_PENDING)
+ {
+ ret = WaitForSingleObject( dir, 1000 );
+ ok( ret == WAIT_OBJECT_0, "WaitForSingleObject error %u\n", ret );
+ ok( U(io).Status == STATUS_INVALID_DEVICE_REQUEST,
+ "expected STATUS_INVALID_DEVICE_REQUEST, got %08x\n", U(io).Status );
+ }
+
+ U(io).Status = 0xdeadbeef;
+ offset.QuadPart = 0;
+ status = pNtWriteFile( dir, NULL, NULL, NULL, &io, testdata, sizeof(testdata), &offset, NULL);
+ todo_wine
+ ok( status == STATUS_INVALID_DEVICE_REQUEST || status == STATUS_PENDING, "NtWriteFile error %08x\n", status );
+ if (status == STATUS_PENDING)
+ {
+ ret = WaitForSingleObject( dir, 1000 );
+ ok( ret == WAIT_OBJECT_0, "WaitForSingleObject error %u\n", ret );
+ ok( U(io).Status == STATUS_INVALID_DEVICE_REQUEST,
+ "expected STATUS_INVALID_DEVICE_REQUEST, got %08x\n", U(io).Status );
+ }
+
CloseHandle( dir );
status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
ok(status == STATUS_OBJECT_NAME_INVALID,
"open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status);
+ pRtlFreeUnicodeString(&nameW);
pRtlDosPathNameToNtPathName_U(pipeInvalidNameW, &nameW, NULL, NULL);
attr.ObjectName = &nameW;
FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
ok(status == STATUS_OBJECT_NAME_INVALID,
"open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status);
+ pRtlFreeUnicodeString(&nameW);
+
+ pRtlInitUnicodeString( &nameW, pathInvalidNtW );
+ status = pNtCreateFile( &dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0,
+ FILE_SHARE_READ, FILE_CREATE,
+ FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
+ ok( status == STATUS_OBJECT_NAME_INVALID,
+ "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+
+ status = pNtQueryFullAttributesFile( &attr, &info );
+ todo_wine ok( status == STATUS_OBJECT_NAME_INVALID,
+ "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+
+ pRtlInitUnicodeString( &nameW, pathInvalidNt2W );
+ status = pNtCreateFile( &dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0,
+ FILE_SHARE_READ, FILE_CREATE,
+ FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
+ ok( status == STATUS_OBJECT_NAME_INVALID,
+ "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+
+ status = pNtQueryFullAttributesFile( &attr, &info );
+ ok( status == STATUS_OBJECT_NAME_INVALID,
+ "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+
+ pRtlInitUnicodeString( &nameW, pathInvalidDosW );
+ status = pNtCreateFile( &dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0,
+ FILE_SHARE_READ, FILE_CREATE,
+ FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
+ ok( status == STATUS_OBJECT_NAME_INVALID,
+ "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+
+ status = pNtQueryFullAttributesFile( &attr, &info );
+ ok( status == STATUS_OBJECT_NAME_INVALID,
+ "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
}
static void open_file_test(void)
{
+ static const char testdata[] = "Hello World";
+ static WCHAR fooW[] = {'f','o','o',0};
NTSTATUS status;
- HANDLE dir, root, handle;
- WCHAR path[MAX_PATH];
+ HANDLE dir, root, handle, file;
+ WCHAR path[MAX_PATH], tmpfile[MAX_PATH];
BYTE data[1024];
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
UNICODE_STRING nameW;
UINT i, len;
- BOOL restart = TRUE;
+ BOOL ret, restart = TRUE;
+ DWORD numbytes;
len = GetWindowsDirectoryW( path, MAX_PATH );
pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL );
CloseHandle( dir );
CloseHandle( root );
+
+ GetTempPathW( MAX_PATH, path );
+ GetTempFileNameW( path, fooW, 0, tmpfile );
+ pRtlDosPathNameToNtPathName_U( tmpfile, &nameW, NULL, NULL );
+
+ file = CreateFileW( tmpfile, FILE_WRITE_DATA, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError() );
+ numbytes = 0xdeadbeef;
+ ret = WriteFile( file, testdata, sizeof(testdata) - 1, &numbytes, NULL );
+ ok( ret, "WriteFile failed with error %u\n", GetLastError() );
+ ok( numbytes == sizeof(testdata) - 1, "failed to write all data\n" );
+ CloseHandle( file );
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.ObjectName = &nameW;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ status = pNtOpenFile( &file, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io,
+ FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT );
+ ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+ pRtlFreeUnicodeString( &nameW );
+
+ numbytes = 0xdeadbeef;
+ memset( data, 0, sizeof(data) );
+ ret = ReadFile( file, data, sizeof(data), &numbytes, NULL );
+ ok( ret, "ReadFile failed with error %u\n", GetLastError() );
+ ok( numbytes == sizeof(testdata) - 1, "failed to read all data\n" );
+ ok( !memcmp( data, testdata, sizeof(testdata) - 1 ), "testdata doesn't match\n" );
+
+ nameW.Length = sizeof(fooW) - sizeof(WCHAR);
+ nameW.Buffer = fooW;
+ attr.RootDirectory = file;
+ attr.ObjectName = &nameW;
+ status = pNtOpenFile( &root, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io,
+ FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT );
+ ok( status == STATUS_OBJECT_PATH_NOT_FOUND,
+ "expected STATUS_OBJECT_PATH_NOT_FOUND, got %08x\n", status );
+
+ nameW.Length = 0;
+ nameW.Buffer = NULL;
+ attr.RootDirectory = file;
+ attr.ObjectName = &nameW;
+ status = pNtOpenFile( &root, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io,
+ FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT );
+ ok( !status, "open %s failed %x\n", wine_dbgstr_w(tmpfile), status );
+
+ numbytes = SetFilePointer( file, 0, 0, FILE_CURRENT );
+ ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes );
+ numbytes = SetFilePointer( root, 0, 0, FILE_CURRENT );
+ ok( numbytes == 0, "SetFilePointer returned %u\n", numbytes );
+
+ numbytes = 0xdeadbeef;
+ memset( data, 0, sizeof(data) );
+ ret = ReadFile( root, data, sizeof(data), &numbytes, NULL );
+ ok( ret, "ReadFile failed with error %u\n", GetLastError() );
+ ok( numbytes == sizeof(testdata) - 1, "failed to read all data\n" );
+ ok( !memcmp( data, testdata, sizeof(testdata) - 1 ), "testdata doesn't match\n" );
+
+ numbytes = SetFilePointer( file, 0, 0, FILE_CURRENT );
+ ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes );
+ numbytes = SetFilePointer( root, 0, 0, FILE_CURRENT );
+ ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes );
+
+ CloseHandle( file );
+ CloseHandle( root );
+ DeleteFileW( tmpfile );
}
static void delete_file_test(void)
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
ok( is_signaled( event ), "event is signaled\n" );
- todo_wine ok( !apc_count, "apc was called\n" );
+ ok( !apc_count, "apc was called\n" );
SleepEx( 1, TRUE ); /* alertable sleep */
ok( apc_count == 1, "apc was not called\n" );
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
ok( is_signaled( event ), "event is signaled\n" );
- todo_wine ok( !apc_count, "apc was called\n" );
+ ok( !apc_count, "apc was called\n" );
SleepEx( 1, TRUE ); /* alertable sleep */
ok( apc_count == 1, "apc was not called\n" );
CloseHandle( handle );
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
ok( is_signaled( event ), "event is signaled\n" );
- todo_wine ok( !apc_count, "apc was called\n" );
+ ok( !apc_count, "apc was called\n" );
SleepEx( 1, TRUE ); /* alertable sleep */
ok( apc_count == 1, "apc was not called\n" );
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
ok( is_signaled( event ), "event is signaled\n" );
- todo_wine ok( !apc_count, "apc was called\n" );
+ ok( !apc_count, "apc was called\n" );
SleepEx( 1, TRUE ); /* alertable sleep */
ok( apc_count == 2, "apc was not called\n" );
CloseHandle( hPipeClt );
}
+static void test_file_full_size_information(void)
+{
+ IO_STATUS_BLOCK io;
+ FILE_FS_FULL_SIZE_INFORMATION ffsi;
+ FILE_FS_SIZE_INFORMATION fsi;
+ HANDLE h;
+ NTSTATUS res;
+
+ if(!(h = create_temp_file(0))) return ;
+
+ memset(&ffsi,0,sizeof(ffsi));
+ memset(&fsi,0,sizeof(fsi));
+
+ /* Assume No Quota Settings configured on Wine Testbot */
+ res = pNtQueryVolumeInformationFile(h, &io, &ffsi, sizeof ffsi, FileFsFullSizeInformation);
+ ok(res == STATUS_SUCCESS, "cannot get attributes, res %x\n", res);
+ res = pNtQueryVolumeInformationFile(h, &io, &fsi, sizeof fsi, FileFsSizeInformation);
+ ok(res == STATUS_SUCCESS, "cannot get attributes, res %x\n", res);
+
+ /* Test for FileFsSizeInformation */
+ ok(fsi.TotalAllocationUnits.QuadPart > 0,
+ "[fsi] TotalAllocationUnits expected positive, got 0x%s\n",
+ debugstr_longlong(fsi.TotalAllocationUnits.QuadPart));
+ ok(fsi.AvailableAllocationUnits.QuadPart > 0,
+ "[fsi] AvailableAllocationUnits expected positive, got 0x%s\n",
+ debugstr_longlong(fsi.AvailableAllocationUnits.QuadPart));
+
+ /* Assume file system is NTFS */
+ ok(fsi.BytesPerSector == 512, "[fsi] BytesPerSector expected 512, got %d\n",fsi.BytesPerSector);
+ ok(fsi.SectorsPerAllocationUnit == 8, "[fsi] SectorsPerAllocationUnit expected 8, got %d\n",fsi.SectorsPerAllocationUnit);
+
+ ok(ffsi.TotalAllocationUnits.QuadPart > 0,
+ "[ffsi] TotalAllocationUnits expected positive, got negative value 0x%s\n",
+ debugstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
+ ok(ffsi.CallerAvailableAllocationUnits.QuadPart > 0,
+ "[ffsi] CallerAvailableAllocationUnits expected positive, got negative value 0x%s\n",
+ debugstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
+ ok(ffsi.ActualAvailableAllocationUnits.QuadPart > 0,
+ "[ffsi] ActualAvailableAllocationUnits expected positive, got negative value 0x%s\n",
+ debugstr_longlong(ffsi.ActualAvailableAllocationUnits.QuadPart));
+ ok(ffsi.TotalAllocationUnits.QuadPart == fsi.TotalAllocationUnits.QuadPart,
+ "[ffsi] TotalAllocationUnits error fsi:0x%s, ffsi:0x%s\n",
+ debugstr_longlong(fsi.TotalAllocationUnits.QuadPart),
+ debugstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
+ ok(ffsi.CallerAvailableAllocationUnits.QuadPart == fsi.AvailableAllocationUnits.QuadPart,
+ "[ffsi] CallerAvailableAllocationUnits error fsi:0x%s, ffsi: 0x%s\n",
+ debugstr_longlong(fsi.AvailableAllocationUnits.QuadPart),
+ debugstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
+
+ /* Assume file system is NTFS */
+ ok(ffsi.BytesPerSector == 512, "[ffsi] BytesPerSector expected 512, got %d\n",ffsi.BytesPerSector);
+ ok(ffsi.SectorsPerAllocationUnit == 8, "[ffsi] SectorsPerAllocationUnit expected 8, got %d\n",ffsi.SectorsPerAllocationUnit);
+
+ CloseHandle( h );
+}
+
static void test_file_basic_information(void)
{
IO_STATUS_BLOCK io;
memset(&fbi, 0, sizeof(fbi));
res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
- todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fbi.FileAttributes );
+ ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM (ok in old linux without xattr)\n", fbi.FileAttributes );
/* Then HIDDEN */
memset(&fbi, 0, sizeof(fbi));
memset(&fbi, 0, sizeof(fbi));
res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
- todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fbi.FileAttributes );
+ ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN (ok in old linux without xattr)\n", fbi.FileAttributes );
/* Check NORMAL last of all (to make sure we can clear attributes) */
memset(&fbi, 0, sizeof(fbi));
memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res);
- todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fai_buf.fai.BasicInformation.FileAttributes );
+ ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM (ok in old linux without xattr)\n", fai_buf.fai.BasicInformation.FileAttributes );
/* Then HIDDEN */
memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
- todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fai_buf.fai.BasicInformation.FileAttributes );
+ ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN (ok in old linux without xattr)\n", fai_buf.fai.BasicInformation.FileAttributes );
/* Check NORMAL last of all (to make sure we can clear attributes) */
memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
CloseHandle( h );
}
+static void delete_object( WCHAR *path )
+{
+ BOOL ret = DeleteFileW( path );
+ ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED,
+ "DeleteFileW failed with %u\n", GetLastError() );
+ if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
+ {
+ ret = RemoveDirectoryW( path );
+ ok( ret, "RemoveDirectoryW failed with %u\n", GetLastError() );
+ }
+}
+
+static void test_file_rename_information(void)
+{
+ static const WCHAR foo_txtW[] = {'\\','f','o','o','.','t','x','t',0};
+ static const WCHAR fooW[] = {'f','o','o',0};
+ WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16], *filename, *p;
+ FILE_RENAME_INFORMATION *fri;
+ FILE_NAME_INFORMATION *fni;
+ BOOL success, fileDeleted;
+ UNICODE_STRING name_str;
+ HANDLE handle, handle2;
+ IO_STATUS_BLOCK io;
+ NTSTATUS res;
+
+ GetTempPathW( MAX_PATH, tmp_path );
+
+ /* oldpath is a file, newpath doesn't exist */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ DeleteFileW( newpath );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "file should not exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) );
+ res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
+ ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
+ wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
+ HeapFree( GetProcessHeap(), 0, fni );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a file, Replace = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a file, Replace = TRUE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = TRUE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "file should not exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a file, Replace = FALSE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a file, Replace = TRUE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = TRUE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath doesn't exist, Replace = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ DeleteFileW( newpath );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "file should not exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) );
+ res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
+ ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
+ wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
+ HeapFree( GetProcessHeap(), 0, fni );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory (but child object opened), newpath doesn't exist, Replace = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ lstrcpyW( newpath, oldpath );
+ lstrcatW( newpath, foo_txtW );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ DeleteFileW( newpath );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ todo_wine ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ todo_wine ok( fileDeleted, "file should not exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ if (res == STATUS_SUCCESS) /* remove when Wine is fixed */
+ {
+ lstrcpyW( oldpath, newpath );
+ lstrcatW( oldpath, foo_txtW );
+ delete_object( oldpath );
+ }
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a file, Replace = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a file, Replace = FALSE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a file, Replace = TRUE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = TRUE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "file should not exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a file, Replace = TRUE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = TRUE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a directory, Replace = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a directory, Replace = TRUE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = TRUE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a directory, Replace = TRUE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = TRUE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a directory, Replace = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = FALSE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a directory, Replace = TRUE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length );
+ fri->Replace = TRUE;
+ fri->RootDir = NULL;
+ fri->FileNameLength = name_str.Length;
+ memcpy( fri->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath doesn't exist, test with RootDir != NULL */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ for (filename = newpath, p = newpath; *p; p++)
+ if (*p == '\\') filename = p + 1;
+ handle2 = CreateFileW( tmp_path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + lstrlenW(filename) * sizeof(WCHAR) );
+ fri->Replace = FALSE;
+ fri->RootDir = handle2;
+ fri->FileNameLength = lstrlenW(filename) * sizeof(WCHAR);
+ memcpy( fri->FileName, filename, fri->FileNameLength );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation );
+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "file should not exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) );
+ res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
+ ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
+ wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
+ HeapFree( GetProcessHeap(), 0, fni );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fri );
+ delete_object( oldpath );
+ delete_object( newpath );
+}
+
+static void test_file_link_information(void)
+{
+ static const WCHAR foo_txtW[] = {'\\','f','o','o','.','t','x','t',0};
+ static const WCHAR fooW[] = {'f','o','o',0};
+ WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16], *filename, *p;
+ FILE_LINK_INFORMATION *fli;
+ FILE_NAME_INFORMATION *fni;
+ BOOL success, fileDeleted;
+ UNICODE_STRING name_str;
+ HANDLE handle, handle2;
+ IO_STATUS_BLOCK io;
+ NTSTATUS res;
+
+ GetTempPathW( MAX_PATH, tmp_path );
+
+ /* oldpath is a file, newpath doesn't exist */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ DeleteFileW( newpath );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) );
+ res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
+ ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
+ wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
+ HeapFree( GetProcessHeap(), 0, fni );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a file, ReplaceIfExists = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a file, ReplaceIfExists = TRUE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = TRUE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a file, ReplaceIfExists = FALSE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a file, ReplaceIfExists = TRUE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = TRUE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath doesn't exist, ReplaceIfExists = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ DeleteFileW( newpath );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef , "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "file should not exist\n" );
+
+ fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) );
+ res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
+ ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
+ wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
+ HeapFree( GetProcessHeap(), 0, fni );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory (but child object opened), newpath doesn't exist, ReplaceIfExists = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ lstrcpyW( newpath, oldpath );
+ lstrcatW( newpath, foo_txtW );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ DeleteFileW( newpath );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "file should not exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a file, ReplaceIfExists = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */,
+ "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a file, ReplaceIfExists = FALSE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */,
+ "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a file, ReplaceIfExists = TRUE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = TRUE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a file, ReplaceIfExists = TRUE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = TRUE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a directory, ReplaceIfExists = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */,
+ "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a directory, ReplaceIfExists = TRUE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = TRUE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a directory, newpath is a directory, ReplaceIfExists = TRUE, target file opened */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( oldpath );
+ success = CreateDirectoryW( oldpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = TRUE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a directory, ReplaceIfExists = FALSE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath is a directory, ReplaceIfExists = TRUE */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ success = CreateDirectoryW( newpath, NULL );
+ ok( success != 0, "failed to create temp directory\n" );
+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL );
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length );
+ fli->ReplaceIfExists = TRUE;
+ fli->RootDirectory = NULL;
+ fli->FileNameLength = name_str.Length;
+ memcpy( fli->FileName, name_str.Buffer, name_str.Length );
+ pRtlFreeUnicodeString( &name_str );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status );
+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+
+ /* oldpath is a file, newpath doesn't exist, test with RootDirectory != NULL */
+ res = GetTempFileNameW( tmp_path, fooW, 0, oldpath );
+ ok( res != 0, "failed to create temp file\n" );
+ handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath );
+ ok( res != 0, "failed to create temp file\n" );
+ DeleteFileW( newpath );
+ for (filename = newpath, p = newpath; *p; p++)
+ if (*p == '\\') filename = p + 1;
+ handle2 = CreateFileW( tmp_path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
+
+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + lstrlenW(filename) * sizeof(WCHAR) );
+ fli->ReplaceIfExists = FALSE;
+ fli->RootDirectory = handle2;
+ fli->FileNameLength = lstrlenW(filename) * sizeof(WCHAR);
+ memcpy( fli->FileName, filename, fli->FileNameLength );
+
+ U(io).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation );
+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+ fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "file should exist\n" );
+
+ fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) );
+ res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
+ ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
+ wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
+ HeapFree( GetProcessHeap(), 0, fni );
+
+ CloseHandle( handle );
+ CloseHandle( handle2 );
+ HeapFree( GetProcessHeap(), 0, fli );
+ delete_object( oldpath );
+ delete_object( newpath );
+}
+
static void test_file_both_information(void)
{
IO_STATUS_BLOCK io;
{
char tmp_path[MAX_PATH], buffer[MAX_PATH + 16];
DWORD dirpos;
- HANDLE handle, handle2;
+ HANDLE handle, handle2, mapping;
NTSTATUS res;
IO_STATUS_BLOCK io;
FILE_DISPOSITION_INFORMATION fdi;
BOOL fileDeleted;
+ DWORD fdi2;
+ void *ptr;
GetTempPathA( MAX_PATH, tmp_path );
+ /* tests for info struct size */
+ GetTempFileNameA( tmp_path, "dis", 0, buffer );
+ handle = CreateFileA( buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+ ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
+ res = pNtSetInformationFile( handle, &io, &fdi, 0, FileDispositionInformation );
+ todo_wine
+ ok( res == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %x\n", res );
+ fdi2 = 0x100;
+ res = pNtSetInformationFile( handle, &io, &fdi2, sizeof(fdi2), FileDispositionInformation );
+ ok( res == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %x\n", res );
+ CloseHandle( handle );
+ fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "File shouldn't have been deleted\n" );
+ DeleteFileA( buffer );
+
/* cannot set disposition on file not opened with delete access */
GetTempFileNameA( tmp_path, "dis", 0, buffer );
handle = CreateFileA(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
ok( res == STATUS_INVALID_INFO_CLASS || res == STATUS_NOT_IMPLEMENTED, "Unexpected NtQueryInformationFile result (expected STATUS_INVALID_INFO_CLASS, got %x)\n", res );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_ACCESS_DENIED, "unexpected FileDispositionInformation result (expected STATUS_ACCESS_DENIED, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
- todo_wine
ok( fileDeleted, "File should have been deleted\n" );
DeleteFileA( buffer );
+ /* cannot set disposition on readonly file */
+ GetTempFileNameA( tmp_path, "dis", 0, buffer );
+ DeleteFileA( buffer );
+ handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
+ ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
+ fdi.DoDeleteFile = TRUE;
+ res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
+ ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
+ CloseHandle( handle );
+ fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "File shouldn't have been deleted\n" );
+ SetFileAttributesA( buffer, FILE_ATTRIBUTE_NORMAL );
+ DeleteFileA( buffer );
+
/* cannot set disposition on readonly file */
GetTempFileNameA( tmp_path, "dis", 0, buffer );
handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ todo_wine
ok( !fileDeleted, "File shouldn't have been deleted\n" );
SetFileAttributesA( buffer, FILE_ATTRIBUTE_NORMAL );
DeleteFileA( buffer );
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
CloseHandle( handle );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle2, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle2 );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( handle != INVALID_HANDLE_VALUE, "failed to open a directory\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
- todo_wine
ok( fileDeleted, "Directory should have been deleted\n" );
RemoveDirectoryA( buffer );
RemoveDirectoryA( buffer );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
- todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
buffer[dirpos] = '\0';
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ todo_wine
ok( !fileDeleted, "Directory shouldn't have been deleted\n" );
RemoveDirectoryA( buffer );
+
+ /* cannot set disposition on file with file mapping opened */
+ GetTempFileNameA( tmp_path, "dis", 0, buffer );
+ handle = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0);
+ ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
+ mapping = CreateFileMappingA( handle, NULL, PAGE_READWRITE, 0, 64 * 1024, "DelFileTest" );
+ ok( mapping != NULL, "failed to create file mapping\n");
+ fdi.DoDeleteFile = TRUE;
+ res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
+ ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
+ CloseHandle( handle );
+ fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "File shouldn't have been deleted\n" );
+ CloseHandle( mapping );
+ DeleteFileA( buffer );
+
+ /* can set disposition on file with file mapping closed */
+ GetTempFileNameA( tmp_path, "dis", 0, buffer );
+ handle = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0);
+ ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
+ mapping = CreateFileMappingA( handle, NULL, PAGE_READWRITE, 0, 64 * 1024, "DelFileTest" );
+ ok( mapping != NULL, "failed to create file mapping\n");
+ CloseHandle( mapping );
+ fdi.DoDeleteFile = TRUE;
+ res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
+ ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
+ CloseHandle( handle );
+ fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "File should have been deleted\n" );
+ DeleteFileA( buffer );
+
+ /* cannot set disposition on file which is mapped to memory */
+ GetTempFileNameA( tmp_path, "dis", 0, buffer );
+ handle = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0);
+ ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
+ mapping = CreateFileMappingA( handle, NULL, PAGE_READWRITE, 0, 64 * 1024, "DelFileTest" );
+ ok( mapping != NULL, "failed to create file mapping\n");
+ ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
+ ok( ptr != NULL, "MapViewOfFile failed\n");
+ CloseHandle( mapping );
+ fdi.DoDeleteFile = TRUE;
+ res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
+ ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
+ CloseHandle( handle );
+ fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( !fileDeleted, "File shouldn't have been deleted\n" );
+ UnmapViewOfFile( ptr );
+ DeleteFileA( buffer );
+
+ /* can set disposition on file which is mapped to memory and unmapped again */
+ GetTempFileNameA( tmp_path, "dis", 0, buffer );
+ handle = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0);
+ ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
+ mapping = CreateFileMappingA( handle, NULL, PAGE_READWRITE, 0, 64 * 1024, "DelFileTest" );
+ ok( mapping != NULL, "failed to create file mapping\n");
+ ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
+ ok( ptr != NULL, "MapViewOfFile failed\n");
+ CloseHandle( mapping );
+ UnmapViewOfFile( ptr );
+ fdi.DoDeleteFile = TRUE;
+ res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
+ ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
+ CloseHandle( handle );
+ fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
+ ok( fileDeleted, "File should have been deleted\n" );
+ DeleteFileA( buffer );
}
static void test_iocompletion(void)
ffvi = (FILE_FS_VOLUME_INFORMATION *)buf;
-todo_wine
-{
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %d\n", status);
ok(U(io).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %d\n", U(io).Status);
+todo_wine
+{
ok(io.Information == (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength),
"expected %d, got %lu\n", (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength),
io.Information);
}
}
+ pRtlFreeUnicodeString( &nameW );
SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE);
DeleteFileW( path );
}
+static void test_readonly(void)
+{
+ static const WCHAR fooW[] = {'f','o','o',0};
+ NTSTATUS status;
+ HANDLE handle;
+ WCHAR path[MAX_PATH];
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ UNICODE_STRING nameW;
+
+ GetTempPathW(MAX_PATH, path);
+ GetTempFileNameW(path, fooW, 0, path);
+ DeleteFileW(path);
+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL);
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = NULL;
+ attr.ObjectName = &nameW;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ status = pNtCreateFile(&handle, GENERIC_READ, &attr, &io, NULL, FILE_ATTRIBUTE_READONLY,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_CREATE, 0, NULL, 0);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, GENERIC_WRITE, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_ACCESS_DENIED, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, GENERIC_READ, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, FILE_READ_ATTRIBUTES, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, FILE_WRITE_ATTRIBUTES, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, DELETE, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, READ_CONTROL, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, WRITE_DAC, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, WRITE_OWNER, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle(handle);
+
+ status = pNtOpenFile(&handle, SYNCHRONIZE, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT);
+ ok(status == STATUS_SUCCESS, "got %#x\n", status);
+ CloseHandle( handle );
+
+ pRtlFreeUnicodeString(&nameW);
+ SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE);
+ DeleteFileW(path);
+}
+
static void test_read_write(void)
{
static const char contents[14] = "1234567890abcd";
ret = ReadFile(hfile, buf, 0, &bytes, &ovl);
/* ReadFile return value depends on Windows version and testing it is not practical */
if (!ret)
-todo_wine
ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError());
ret = GetLastError();
ok(bytes == 0, "bytes %u\n", bytes);
ret = ReadFile(hfile, NULL, 0, &bytes, &ovl);
/* ReadFile return value depends on Windows version and testing it is not practical */
if (!ret)
-todo_wine
ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError());
ret = GetLastError();
ok(bytes == 0, "bytes %u\n", bytes);
{
ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError());
ok(bytes == 0, "bytes %u\n", bytes);
+ ret = WaitForSingleObject(hfile, 3000);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret);
}
else ok(bytes == 4, "bytes %u\n", bytes);
ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal);
{
ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError());
ok(bytes == 0, "bytes %u\n", bytes);
+ ret = WaitForSingleObject(hfile, 3000);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret);
}
else ok(bytes == 14, "bytes %u\n", bytes);
ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal);
CloseHandle(hfile);
}
+static void test_query_ea(void)
+{
+ #define EA_BUFFER_SIZE 4097
+ unsigned char data[EA_BUFFER_SIZE + 8];
+ unsigned char *buffer = (void *)(((DWORD_PTR)data + 7) & ~7);
+ DWORD buffer_len, i;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ HANDLE handle;
+
+ if (!(handle = create_temp_file(0))) return;
+
+ /* test with INVALID_HANDLE_VALUE */
+ U(io).Status = 0xdeadbeef;
+ io.Information = 0xdeadbeef;
+ memset(buffer, 0xcc, EA_BUFFER_SIZE);
+ buffer_len = EA_BUFFER_SIZE - 1;
+ status = pNtQueryEaFile(INVALID_HANDLE_VALUE, &io, buffer, buffer_len, TRUE, NULL, 0, NULL, FALSE);
+ ok(status == STATUS_OBJECT_TYPE_MISMATCH, "expected STATUS_OBJECT_TYPE_MISMATCH, got %x\n", status);
+ ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status);
+ ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information);
+ ok(buffer[0] == 0xcc, "data at position 0 overwritten\n");
+
+ /* test with 0xdeadbeef */
+ U(io).Status = 0xdeadbeef;
+ io.Information = 0xdeadbeef;
+ memset(buffer, 0xcc, EA_BUFFER_SIZE);
+ buffer_len = EA_BUFFER_SIZE - 1;
+ status = pNtQueryEaFile((void *)0xdeadbeef, &io, buffer, buffer_len, TRUE, NULL, 0, NULL, FALSE);
+ ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %x\n", status);
+ ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status);
+ ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information);
+ ok(buffer[0] == 0xcc, "data at position 0 overwritten\n");
+
+ /* test without buffer */
+ U(io).Status = 0xdeadbeef;
+ io.Information = 0xdeadbeef;
+ status = pNtQueryEaFile(handle, &io, NULL, 0, TRUE, NULL, 0, NULL, FALSE);
+ ok(status == STATUS_NO_EAS_ON_FILE, "expected STATUS_NO_EAS_ON_FILE, got %x\n", status);
+ ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status);
+ ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information);
+
+ /* test with zero buffer */
+ U(io).Status = 0xdeadbeef;
+ io.Information = 0xdeadbeef;
+ status = pNtQueryEaFile(handle, &io, buffer, 0, TRUE, NULL, 0, NULL, FALSE);
+ ok(status == STATUS_NO_EAS_ON_FILE, "expected STATUS_NO_EAS_ON_FILE, got %x\n", status);
+ ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status);
+ ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information);
+
+ /* test with very small buffer */
+ U(io).Status = 0xdeadbeef;
+ io.Information = 0xdeadbeef;
+ memset(buffer, 0xcc, EA_BUFFER_SIZE);
+ buffer_len = 4;
+ status = pNtQueryEaFile(handle, &io, buffer, buffer_len, TRUE, NULL, 0, NULL, FALSE);
+ ok(status == STATUS_NO_EAS_ON_FILE, "expected STATUS_NO_EAS_ON_FILE, got %x\n", status);
+ ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status);
+ ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information);
+ for (i = 0; i < buffer_len && !buffer[i]; i++);
+ ok(i == buffer_len, "expected %u bytes filled with 0x00, got %u bytes\n", buffer_len, i);
+ ok(buffer[i] == 0xcc, "data at position %u overwritten\n", buffer[i]);
+
+ /* test with very big buffer */
+ U(io).Status = 0xdeadbeef;
+ io.Information = 0xdeadbeef;
+ memset(buffer, 0xcc, EA_BUFFER_SIZE);
+ buffer_len = EA_BUFFER_SIZE - 1;
+ status = pNtQueryEaFile(handle, &io, buffer, buffer_len, TRUE, NULL, 0, NULL, FALSE);
+ ok(status == STATUS_NO_EAS_ON_FILE, "expected STATUS_NO_EAS_ON_FILE, got %x\n", status);
+ ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status);
+ ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information);
+ for (i = 0; i < buffer_len && !buffer[i]; i++);
+ ok(i == buffer_len, "expected %u bytes filled with 0x00, got %u bytes\n", buffer_len, i);
+ ok(buffer[i] == 0xcc, "data at position %u overwritten\n", buffer[i]);
+
+ CloseHandle(handle);
+ #undef EA_BUFFER_SIZE
+}
+
+static INT build_reparse_buffer(WCHAR *filename, REPARSE_DATA_BUFFER **pbuffer)
+{
+ REPARSE_DATA_BUFFER *buffer;
+ INT buffer_len, string_len;
+ WCHAR *dest;
+
+ string_len = (lstrlenW(filename)+1)*sizeof(WCHAR);
+ buffer_len = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[1]) + string_len;
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ buffer->ReparseDataLength = sizeof(buffer->MountPointReparseBuffer) + string_len;
+ buffer->MountPointReparseBuffer.SubstituteNameLength = string_len - sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameOffset = string_len;
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[0];
+ memcpy(dest, filename, string_len);
+ *pbuffer = buffer;
+ return buffer_len;
+}
+
+static void test_junction_points(void)
+{
+ static const WCHAR junctionW[] = {'\\','j','u','n','c','t','i','o','n',0};
+ WCHAR path[MAX_PATH], junction_path[MAX_PATH], target_path[MAX_PATH];
+ static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
+ FILE_BASIC_INFORMATION old_attrib, new_attrib;
+ static const WCHAR fooW[] = {'f','o','o',0};
+ static WCHAR volW[] = {'c',':','\\',0};
+ REPARSE_GUID_DATA_BUFFER guid_buffer;
+ static const WCHAR dotW[] = {'.',0};
+ REPARSE_DATA_BUFFER *buffer = NULL;
+ DWORD dwret, dwLen, dwFlags, err;
+ INT buffer_len, string_len;
+ IO_STATUS_BLOCK iosb;
+ UNICODE_STRING nameW;
+ HANDLE hJunction;
+ WCHAR *dest;
+ BOOL bret;
+
+ /* Create a temporary folder for the junction point tests */
+ GetTempFileNameW(dotW, fooW, 0, path);
+ DeleteFileW(path);
+ if (!CreateDirectoryW(path, NULL))
+ {
+ win_skip("Unable to create a temporary junction point directory.\n");
+ return;
+ }
+
+ /* Check that the volume this folder is located on supports junction points */
+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL);
+ volW[0] = nameW.Buffer[4];
+ pRtlFreeUnicodeString( &nameW );
+ GetVolumeInformationW(volW, 0, 0, 0, &dwLen, &dwFlags, 0, 0);
+ if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS))
+ {
+ skip("File system does not support junction points.\n");
+ RemoveDirectoryW(path);
+ return;
+ }
+
+ /* Create the folder to be replaced by a junction point */
+ lstrcpyW(junction_path, path);
+ lstrcatW(junction_path, junctionW);
+ bret = CreateDirectoryW(junction_path, NULL);
+ ok(bret, "Failed to create junction point directory.\n");
+
+ /* Create a destination folder for the junction point to target */
+ lstrcpyW(target_path, path);
+ lstrcatW(target_path, targetW);
+ bret = CreateDirectoryW(target_path, NULL);
+ ok(bret, "Failed to create junction point target directory.\n");
+ pRtlDosPathNameToNtPathName_U(target_path, &nameW, NULL, NULL);
+
+ /* Create the junction point */
+ hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (hJunction == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open junction point directory handle (0x%x).\n", GetLastError());
+ goto cleanup;
+ }
+ dwret = NtQueryInformationFile(hJunction, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%x).\n", dwret);
+ buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
+ bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
+
+ /* Check the file attributes of the junction point */
+ dwret = GetFileAttributesW(junction_path);
+ ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: %d)\n", dwret);
+
+ /* Read back the junction point */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR);
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
+ bret = DeviceIoControl(hJunction, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
+ string_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ ok(bret, "Failed to read junction point!\n");
+ ok((memcmp(dest, nameW.Buffer, string_len) == 0), "Junction point destination does not match ('%s' != '%s')!\n",
+ wine_dbgstr_w(dest), wine_dbgstr_w(nameW.Buffer));
+
+ /* Delete the junction point */
+ memset(&old_attrib, 0x00, sizeof(old_attrib));
+ old_attrib.LastAccessTime.QuadPart = 0x200deadcafebeef;
+ dwret = NtSetInformationFile(hJunction, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to set junction point folder's attributes (0x%x).\n", dwret);
+ memset(&guid_buffer, 0x00, sizeof(guid_buffer));
+ guid_buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ bret = DeviceIoControl(hJunction, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer,
+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to delete junction point! (0x%x)\n", GetLastError());
+ memset(&new_attrib, 0x00, sizeof(new_attrib));
+ dwret = NtQueryInformationFile(hJunction, &iosb, &new_attrib, sizeof(new_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%x).\n", dwret);
+ ok(old_attrib.LastAccessTime.QuadPart == new_attrib.LastAccessTime.QuadPart,
+ "Junction point folder's access time does not match (0x%llx != 0x%llx).\n",
+ new_attrib.LastAccessTime.QuadPart, old_attrib.LastAccessTime.QuadPart);
+ CloseHandle(hJunction);
+
+ /* Check deleting a junction point as if it were a directory */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
+ bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
+ CloseHandle(hJunction);
+ bret = RemoveDirectoryW(junction_path);
+ ok(bret, "Failed to delete junction point as directory!\n");
+ dwret = GetFileAttributesW(junction_path);
+ ok(dwret == (DWORD)~0, "Junction point still exists (attributes: 0x%x)!\n", dwret);
+
+ /* Check deleting a junction point as if it were a file */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ bret = CreateDirectoryW(junction_path, NULL);
+ ok(bret, "Failed to create junction point target directory.\n");
+ hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
+ bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
+ CloseHandle(hJunction);
+ bret = DeleteFileW(junction_path);
+ ok(!bret, "Succeeded in deleting junction point as file!\n");
+ err = GetLastError();
+ ok(err == ERROR_ACCESS_DENIED, "Expected last error 0x%x for DeleteFile on junction point (actually 0x%x)!\n",
+ ERROR_ACCESS_DENIED, err);
+ dwret = GetFileAttributesW(junction_path);
+ ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%x)\n", dwret);
+
+ /* Test deleting a junction point's target */
+ dwret = GetFileAttributesW(junction_path);
+ ok(dwret == 0x410 || broken(dwret == 0x430) /* win2k */,
+ "Unexpected junction point attributes (0x%x != 0x410)!\n", dwret);
+ bret = RemoveDirectoryW(target_path);
+ ok(bret, "Failed to delete junction point target!\n");
+ bret = CreateDirectoryW(target_path, NULL);
+ ok(bret, "Failed to create junction point target directory.\n");
+
+cleanup:
+ /* Cleanup */
+ pRtlFreeUnicodeString( &nameW );
+ HeapFree(GetProcessHeap(), 0, buffer);
+ bret = RemoveDirectoryW(junction_path);
+ ok(bret, "Failed to remove temporary junction point directory!\n");
+ bret = RemoveDirectoryW(target_path);
+ ok(bret, "Failed to remove temporary target directory!\n");
+ RemoveDirectoryW(path);
+}
+
START_TEST(file)
{
HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile");
pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile");
pNtQueryVolumeInformationFile = (void *)GetProcAddress(hntdll, "NtQueryVolumeInformationFile");
+ pNtQueryFullAttributesFile = (void *)GetProcAddress(hntdll, "NtQueryFullAttributesFile");
+ pNtQueryEaFile = (void *)GetProcAddress(hntdll, "NtQueryEaFile");
test_read_write();
test_NtCreateFile();
+ test_readonly();
create_file_test();
open_file_test();
delete_file_test();
test_file_all_information();
test_file_both_information();
test_file_name_information();
+ test_file_full_size_information();
test_file_all_name_information();
+ test_file_rename_information();
+ test_file_link_information();
test_file_disposition_information();
test_query_volume_information_file();
test_query_attribute_information_file();
+ test_query_ea();
+ test_junction_points();
}