mirror of
https://github.com/reactos/reactos.git
synced 2025-01-04 05:20:54 +00:00
[KMTESTS:IO]
Add more tests for IoCreateFile(), this time purely dealing with symlinks reparse points. They won't run on ReactOS (obviously) as we don't have RW NTFS support. On Windows, they show interesting results.... With Windows 2003, creating the symlink is allowed and works, but then Windows is totally unable to deal with it and keeps complaining about an unhandled reparse tag. The only way to open it is to open the reparse point itself. Not that working symlinks... Not sure which part is not able to handle the said reparse tag. NTFS? Io? With Windows Vista+, it just works fine. Symlink is created & functionnal. Broken logic! svn path=/trunk/; revision=69353
This commit is contained in:
parent
9099445189
commit
549ecc5195
1 changed files with 366 additions and 0 deletions
|
@ -420,6 +420,370 @@ KernelModeTest(IN PVOID Context)
|
|||
static
|
||||
VOID
|
||||
NTAPI
|
||||
TestSymlinks(VOID)
|
||||
{
|
||||
HANDLE ReparseHandle;
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
PREPARSE_DATA_BUFFER Reparse;
|
||||
FILE_DISPOSITION_INFORMATION ToDelete;
|
||||
PFILE_OBJECT FileObject;
|
||||
UNICODE_STRING SysDir, Foobar, Regedit;
|
||||
ULONG Size;
|
||||
|
||||
/* Get Windows/ReactOS directory */
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&SystemRoot,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwOpenFile(&ReparseHandle,
|
||||
FILE_READ_DATA,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_DIRECTORY_FILE);
|
||||
if (skip(NT_SUCCESS(Status), "Opening \\SystemRoot failed: %lx\n", Status))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Status = ObReferenceObjectByHandle(ReparseHandle,
|
||||
FILE_READ_DATA,
|
||||
*IoFileObjectType,
|
||||
UserMode,
|
||||
(PVOID *)&FileObject,
|
||||
NULL);
|
||||
if (skip(NT_SUCCESS(Status), "Querying name failed: %lx\n", Status))
|
||||
{
|
||||
ZwClose(ReparseHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
SysDir.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\??\\C:"));
|
||||
if (skip(SysDir.Buffer != NULL, "Allocating memory failed\n"))
|
||||
{
|
||||
ObDereferenceObject(FileObject);
|
||||
ZwClose(ReparseHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
SysDir.Length = sizeof(L"\\??\\C:") - sizeof(UNICODE_NULL);
|
||||
SysDir.MaximumLength = FileObject->FileName.Length + sizeof(L"\\??\\C:");
|
||||
RtlCopyMemory(SysDir.Buffer, L"\\??\\C:", sizeof(L"\\??\\C:") - sizeof(UNICODE_NULL));
|
||||
RtlAppendUnicodeStringToString(&SysDir, &FileObject->FileName);
|
||||
|
||||
Foobar.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\foobar.exe"));
|
||||
if (skip(Foobar.Buffer != NULL, "Allocating memory failed\n"))
|
||||
{
|
||||
ExFreePool(SysDir.Buffer);
|
||||
ObDereferenceObject(FileObject);
|
||||
ZwClose(ReparseHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
Foobar.Length = 0;
|
||||
Foobar.MaximumLength = FileObject->FileName.Length + sizeof(L"\\foobar.exe");
|
||||
RtlCopyUnicodeString(&Foobar, &FileObject->FileName);
|
||||
RtlCopyMemory(&Foobar.Buffer[Foobar.Length / sizeof(WCHAR)], L"\\foobar.exe", sizeof(L"\\foobar.exe") - sizeof(UNICODE_NULL));
|
||||
Foobar.Length += (sizeof(L"\\foobar.exe") - sizeof(UNICODE_NULL));
|
||||
|
||||
Regedit.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\regedit.exe"));
|
||||
if (skip(Regedit.Buffer != NULL, "Allocating memory failed\n"))
|
||||
{
|
||||
ExFreePool(Foobar.Buffer);
|
||||
ExFreePool(SysDir.Buffer);
|
||||
ObDereferenceObject(FileObject);
|
||||
ZwClose(ReparseHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
Regedit.Length = 0;
|
||||
Regedit.MaximumLength = FileObject->FileName.Length + sizeof(L"\\regedit.exe");
|
||||
RtlCopyUnicodeString(&Regedit, &FileObject->FileName);
|
||||
RtlCopyMemory(&Regedit.Buffer[Regedit.Length / sizeof(WCHAR)], L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
|
||||
Regedit.Length += (sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
|
||||
|
||||
ObDereferenceObject(FileObject);
|
||||
ZwClose(ReparseHandle);
|
||||
|
||||
ToDelete.DeleteFile = TRUE;
|
||||
Size = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL);
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&SystemRootFoobar,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwCreateFile(&ReparseHandle,
|
||||
GENERIC_READ | GENERIC_WRITE | DELETE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_SUPERSEDE,
|
||||
FILE_NON_DIRECTORY_FILE,
|
||||
NULL,
|
||||
0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
if (skip(NT_SUCCESS(Status), "Creating file failed: %lx\n", Status))
|
||||
{
|
||||
ExFreePool(Regedit.Buffer);
|
||||
ExFreePool(Foobar.Buffer);
|
||||
ExFreePool(SysDir.Buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
Reparse = ExAllocatePool(NonPagedPool, Size);
|
||||
RtlZeroMemory(Reparse, Size);
|
||||
Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
||||
Reparse->ReparseDataLength = 12 + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL);
|
||||
Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL);
|
||||
Reparse->SymbolicLinkReparseBuffer.PrintNameLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(L"\\??\\");
|
||||
Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset = Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
|
||||
RtlCopyMemory(Reparse->SymbolicLinkReparseBuffer.PathBuffer,
|
||||
(WCHAR *)((ULONG_PTR)SysDir.Buffer + sizeof(L"\\??\\") - sizeof(UNICODE_NULL)),
|
||||
SysDir.Length - sizeof(L"\\??\\") + sizeof(UNICODE_NULL));
|
||||
RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + SysDir.Length - sizeof(L"\\??\\") + sizeof(UNICODE_NULL)),
|
||||
L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
|
||||
RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset),
|
||||
SysDir.Buffer, SysDir.Length);
|
||||
RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset + SysDir.Length),
|
||||
L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
|
||||
|
||||
Status = ZwFsControlFile(ReparseHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
FSCTL_SET_REPARSE_POINT,
|
||||
Reparse,
|
||||
Size,
|
||||
NULL,
|
||||
0);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ZwClose(ReparseHandle);
|
||||
|
||||
Status = ZwCreateFile(&ReparseHandle,
|
||||
FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
FILE_SUPERSEDE,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
|
||||
NULL,
|
||||
0);
|
||||
if (skip(NT_SUCCESS(Status), "Creating symlink failed: %lx\n", Status))
|
||||
{
|
||||
Status = ZwOpenFile(&ReparseHandle,
|
||||
DELETE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_DELETE,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ZwClose(ReparseHandle);
|
||||
ExFreePool(Regedit.Buffer);
|
||||
ExFreePool(Foobar.Buffer);
|
||||
ExFreePool(SysDir.Buffer);
|
||||
ExFreePool(Reparse);
|
||||
return;
|
||||
}
|
||||
|
||||
Status = ZwFsControlFile(ReparseHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
FSCTL_SET_REPARSE_POINT,
|
||||
Reparse,
|
||||
Size,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
if (skip(NT_SUCCESS(Status), "Creating symlink failed: %lx\n", Status))
|
||||
{
|
||||
ZwSetInformationFile(ReparseHandle,
|
||||
&IoStatusBlock,
|
||||
&ToDelete,
|
||||
sizeof(ToDelete),
|
||||
FileDispositionInformation);
|
||||
ZwClose(ReparseHandle);
|
||||
ExFreePool(Regedit.Buffer);
|
||||
ExFreePool(Foobar.Buffer);
|
||||
ExFreePool(SysDir.Buffer);
|
||||
ExFreePool(Reparse);
|
||||
return;
|
||||
}
|
||||
|
||||
ZwClose(ReparseHandle);
|
||||
|
||||
Status = ZwCreateFile(&ReparseHandle,
|
||||
GENERIC_READ,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_OPEN,
|
||||
FILE_NON_DIRECTORY_FILE,
|
||||
NULL,
|
||||
0);
|
||||
ok(Status == STATUS_SUCCESS || /* Windows Vista+ */
|
||||
Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED, /* Windows 2003 (SP1, SP2) */
|
||||
"ZwCreateFile returned unexpected status: %lx\n", Status);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
Status = ObReferenceObjectByHandle(ReparseHandle,
|
||||
FILE_READ_DATA,
|
||||
*IoFileObjectType,
|
||||
UserMode,
|
||||
(PVOID *)&FileObject,
|
||||
NULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ok(RtlCompareUnicodeString(&Regedit, &FileObject->FileName, TRUE) == 0,
|
||||
"Expected: %wZ. Opened: %wZ\n", &Regedit, &FileObject->FileName);
|
||||
ObDereferenceObject(FileObject);
|
||||
}
|
||||
|
||||
ZwClose(ReparseHandle);
|
||||
}
|
||||
|
||||
ExFreePool(Regedit.Buffer);
|
||||
|
||||
Status = IoCreateFile(&ReparseHandle,
|
||||
GENERIC_READ,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_OPEN,
|
||||
FILE_NON_DIRECTORY_FILE,
|
||||
NULL,
|
||||
0,
|
||||
CreateFileTypeNone,
|
||||
NULL,
|
||||
IO_NO_PARAMETER_CHECKING | IO_STOP_ON_SYMLINK);
|
||||
ok(Status == STATUS_STOPPED_ON_SYMLINK || /* Windows Vista+ */
|
||||
Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED, /* Windows 2003 (SP1, SP2) */
|
||||
"ZwCreateFile returned unexpected status: %lx\n", Status);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ZwClose(ReparseHandle);
|
||||
}
|
||||
|
||||
Status = ZwCreateFile(&ReparseHandle,
|
||||
GENERIC_READ | GENERIC_WRITE | DELETE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_OPEN,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT,
|
||||
NULL,
|
||||
0);
|
||||
if (skip(NT_SUCCESS(Status), "Creating opening reparse point: %lx\n", Status))
|
||||
{
|
||||
Status = ZwOpenFile(&ReparseHandle,
|
||||
DELETE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_DELETE,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ZwClose(ReparseHandle);
|
||||
ExFreePool(Foobar.Buffer);
|
||||
ExFreePool(SysDir.Buffer);
|
||||
ExFreePool(Reparse);
|
||||
return;
|
||||
}
|
||||
|
||||
Status = ObReferenceObjectByHandle(ReparseHandle,
|
||||
FILE_READ_DATA,
|
||||
*IoFileObjectType,
|
||||
UserMode,
|
||||
(PVOID *)&FileObject,
|
||||
NULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ok(RtlCompareUnicodeString(&Foobar, &FileObject->FileName, TRUE) == 0,
|
||||
"Expected: %wZ. Opened: %wZ\n", &Foobar, &FileObject->FileName);
|
||||
ObDereferenceObject(FileObject);
|
||||
}
|
||||
|
||||
ExFreePool(Foobar.Buffer);
|
||||
|
||||
RtlZeroMemory(Reparse, Size);
|
||||
Status = ZwFsControlFile(ReparseHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
FSCTL_GET_REPARSE_POINT,
|
||||
NULL,
|
||||
0,
|
||||
Reparse,
|
||||
Size);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex(IoStatusBlock.Information, Size);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
PWSTR Buffer;
|
||||
UNICODE_STRING ReparsePath, FullPath;
|
||||
|
||||
ok_eq_hex(Reparse->ReparseTag, IO_REPARSE_TAG_SYMLINK);
|
||||
ok_eq_hex(Reparse->ReparseDataLength, 12 + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL));
|
||||
ok_eq_hex(Reparse->SymbolicLinkReparseBuffer.Flags, 0);
|
||||
|
||||
FullPath.Length = 0;
|
||||
FullPath.MaximumLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL);
|
||||
Buffer = FullPath.Buffer = ExAllocatePool(NonPagedPool, FullPath.MaximumLength);
|
||||
if (!skip(Buffer != NULL, "Memory allocation failed!\n"))
|
||||
{
|
||||
RtlCopyUnicodeString(&FullPath, &SysDir);
|
||||
RtlCopyMemory(&FullPath.Buffer[FullPath.Length / sizeof(WCHAR)], L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
|
||||
FullPath.Length += (sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
|
||||
ReparsePath.Buffer = (PWSTR)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset);
|
||||
ReparsePath.Length = ReparsePath.MaximumLength = Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||
ok(RtlCompareUnicodeString(&ReparsePath, &FullPath, TRUE) == 0, "Expected: %wZ. Got: %wZ\n", &ReparsePath, &FullPath);
|
||||
|
||||
FullPath.Length -= (sizeof(L"\\??\\") - sizeof(UNICODE_NULL));
|
||||
FullPath.MaximumLength -= (sizeof(L"\\??\\") - sizeof(UNICODE_NULL));
|
||||
FullPath.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(L"\\??\\") - sizeof(UNICODE_NULL));
|
||||
ReparsePath.Buffer = (PWSTR)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||
ReparsePath.Length = ReparsePath.MaximumLength = Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
|
||||
ok(RtlCompareUnicodeString(&ReparsePath, &FullPath, TRUE) == 0, "Expected: %wZ. Got: %wZ\n", &ReparsePath, &FullPath);
|
||||
|
||||
ExFreePool(Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(SysDir.Buffer);
|
||||
ExFreePool(Reparse);
|
||||
|
||||
ZwSetInformationFile(ReparseHandle,
|
||||
&IoStatusBlock,
|
||||
&ToDelete,
|
||||
sizeof(ToDelete),
|
||||
FileDispositionInformation);
|
||||
ZwClose(ReparseHandle);
|
||||
}
|
||||
|
||||
//static
|
||||
VOID
|
||||
NTAPI
|
||||
UserModeTest(VOID)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
@ -512,6 +876,8 @@ START_TEST(IoCreateFile)
|
|||
HANDLE ThreadHandle;
|
||||
PVOID ThreadObject = NULL;
|
||||
|
||||
TestSymlinks();
|
||||
|
||||
/* Justify the next comment/statement */
|
||||
UserModeTest();
|
||||
|
||||
|
|
Loading…
Reference in a new issue