Author: pschweitzer
Date: Fri Sep 25 15:57:28 2015
New Revision: 69353
URL:
http://svn.reactos.org/svn/reactos?rev=69353&view=rev
Log:
[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!
Modified:
trunk/rostests/kmtests/ntos_io/IoCreateFile.c
Modified: trunk/rostests/kmtests/ntos_io/IoCreateFile.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/kmtests/ntos_io/IoCreateF…
==============================================================================
--- trunk/rostests/kmtests/ntos_io/IoCreateFile.c [iso-8859-1] (original)
+++ trunk/rostests/kmtests/ntos_io/IoCreateFile.c [iso-8859-1] Fri Sep 25 15:57:28 2015
@@ -420,6 +420,370 @@
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 @@
HANDLE ThreadHandle;
PVOID ThreadObject = NULL;
+ TestSymlinks();
+
/* Justify the next comment/statement */
UserModeTest();