1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test driver for reparse point operations 5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org> 6 */ 7 8 #include <kmt_test.h> 9 10 #define NDEBUG 11 #include <debug.h> 12 13 #include "IoCreateFile.h" 14 15 typedef struct _TEST_FCB 16 { 17 FSRTL_ADVANCED_FCB_HEADER Header; 18 SECTION_OBJECT_POINTERS SectionObjectPointers; 19 FAST_MUTEX HeaderMutex; 20 } TEST_FCB, *PTEST_FCB; 21 22 static KMT_IRP_HANDLER TestIrpHandler; 23 static KMT_MESSAGE_HANDLER TestMessageHandler; 24 25 static PFILE_OBJECT TestFileObject; 26 static PDEVICE_OBJECT TestDeviceObject; 27 28 NTSTATUS 29 TestEntry( 30 _In_ PDRIVER_OBJECT DriverObject, 31 _In_ PCUNICODE_STRING RegistryPath, 32 _Out_ PCWSTR *DeviceName, 33 _Inout_ INT *Flags) 34 { 35 NTSTATUS Status = STATUS_SUCCESS; 36 37 PAGED_CODE(); 38 39 UNREFERENCED_PARAMETER(RegistryPath); 40 41 *DeviceName = L"IoCreateFile"; 42 *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE | 43 TESTENTRY_BUFFERED_IO_DEVICE | 44 TESTENTRY_NO_READONLY_DEVICE; 45 46 KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler); 47 KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler); 48 KmtRegisterMessageHandler(0, NULL, TestMessageHandler); 49 50 return Status; 51 } 52 53 VOID 54 TestUnload( 55 _In_ PDRIVER_OBJECT DriverObject) 56 { 57 PAGED_CODE(); 58 } 59 60 static volatile long gNoLinks = FALSE; 61 62 static 63 NTSTATUS 64 TestIrpHandler( 65 _In_ PDEVICE_OBJECT DeviceObject, 66 _In_ PIRP Irp, 67 _In_ PIO_STACK_LOCATION IoStack) 68 { 69 NTSTATUS Status; 70 PTEST_FCB Fcb; 71 CACHE_UNINITIALIZE_EVENT CacheUninitEvent; 72 73 PAGED_CODE(); 74 75 DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction); 76 ASSERT(IoStack->MajorFunction == IRP_MJ_CREATE || 77 IoStack->MajorFunction == IRP_MJ_CLEANUP); 78 79 Status = STATUS_NOT_SUPPORTED; 80 Irp->IoStatus.Information = 0; 81 82 if (IoStack->MajorFunction == IRP_MJ_CREATE) 83 { 84 ok((IoStack->Parameters.Create.Options & FILE_OPEN_REPARSE_POINT) == 0, "FILE_OPEN_REPARSE_POINT set\n"); 85 ok((IoStack->Flags == 0 && !gNoLinks) || (IoStack->Flags == SL_STOP_ON_SYMLINK && gNoLinks), "IoStack->Flags = %lx\n", IoStack->Flags); 86 87 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR)) 88 { 89 TestDeviceObject = DeviceObject; 90 TestFileObject = IoStack->FileObject; 91 } 92 if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && 93 IoStack->FileObject->FileName.Buffer[1] == 'M') 94 { 95 PREPARSE_DATA_BUFFER Reparse; 96 97 Irp->Tail.Overlay.AuxiliaryBuffer = ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 'FwrI'); 98 Reparse = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; 99 100 RtlZeroMemory(Reparse, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 101 Reparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; 102 Reparse->ReparseDataLength = 12 + sizeof(L"\\??\\C:\\Documents and Settings"); 103 Reparse->MountPointReparseBuffer.SubstituteNameLength = sizeof(L"\\??\\C:\\Documents and Settings") - sizeof(UNICODE_NULL); 104 Reparse->MountPointReparseBuffer.PrintNameOffset = sizeof(L"\\??\\C:\\Documents and Settings"); 105 RtlCopyMemory(Reparse->MountPointReparseBuffer.PathBuffer, L"\\??\\C:\\Documents and Settings", sizeof(L"\\??\\C:\\Documents and Settings")); 106 Irp->IoStatus.Information = IO_REPARSE_TAG_MOUNT_POINT; 107 Status = STATUS_REPARSE; 108 } 109 else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && 110 IoStack->FileObject->FileName.Buffer[1] == 'S') 111 { 112 if (IoStack->Flags & SL_STOP_ON_SYMLINK) 113 { 114 Status = STATUS_STOPPED_ON_SYMLINK; 115 } 116 else 117 { 118 PREPARSE_DATA_BUFFER Reparse; 119 120 Irp->Tail.Overlay.AuxiliaryBuffer = ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 'FwrI'); 121 Reparse = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; 122 123 RtlZeroMemory(Reparse, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 124 Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK; 125 Reparse->ReparseDataLength = 12 + sizeof(L"\\??\\C:\\Documents and Settings"); 126 Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength = sizeof(L"\\??\\C:\\Documents and Settings") - sizeof(UNICODE_NULL); 127 Reparse->SymbolicLinkReparseBuffer.PrintNameOffset = sizeof(L"\\??\\C:\\Documents and Settings"); 128 RtlCopyMemory(Reparse->SymbolicLinkReparseBuffer.PathBuffer, L"\\??\\C:\\Documents and Settings", sizeof(L"\\??\\C:\\Documents and Settings")); 129 Irp->IoStatus.Information = IO_REPARSE_TAG_SYMLINK; 130 Status = STATUS_REPARSE; 131 } 132 } 133 else 134 { 135 Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI'); 136 RtlZeroMemory(Fcb, sizeof(*Fcb)); 137 ExInitializeFastMutex(&Fcb->HeaderMutex); 138 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex); 139 Fcb->Header.AllocationSize.QuadPart = 0; 140 Fcb->Header.FileSize.QuadPart = 0; 141 Fcb->Header.ValidDataLength.QuadPart = 0; 142 IoStack->FileObject->FsContext = Fcb; 143 IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; 144 145 Irp->IoStatus.Information = FILE_OPENED; 146 Status = STATUS_SUCCESS; 147 } 148 } 149 else if (IoStack->MajorFunction == IRP_MJ_CLEANUP) 150 { 151 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE); 152 CcUninitializeCacheMap(IoStack->FileObject, NULL, &CacheUninitEvent); 153 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL); 154 Fcb = IoStack->FileObject->FsContext; 155 ExFreePoolWithTag(Fcb, 'FwrI'); 156 IoStack->FileObject->FsContext = NULL; 157 Status = STATUS_SUCCESS; 158 } 159 160 Irp->IoStatus.Status = Status; 161 IoCompleteRequest(Irp, IO_NO_INCREMENT); 162 163 return Status; 164 } 165 166 static UNICODE_STRING FileObjectFileName = RTL_CONSTANT_STRING(L"\\NonSymlinked"); 167 static UNICODE_STRING DocumentsAndSettings = RTL_CONSTANT_STRING(L"\\Documents and Settings"); 168 169 static 170 NTSTATUS 171 TestIoCreateFile( 172 IN PUNICODE_STRING Path) 173 { 174 OBJECT_ATTRIBUTES ObjectAttributes; 175 IO_STATUS_BLOCK IoStatusBlock; 176 HANDLE Handle; 177 NTSTATUS Status; 178 PFILE_OBJECT FileObject; 179 180 InitializeObjectAttributes(&ObjectAttributes, 181 Path, 182 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 183 NULL, 184 NULL); 185 Status = IoCreateFile(&Handle, 186 GENERIC_READ, 187 &ObjectAttributes, 188 &IoStatusBlock, 189 NULL, 190 FILE_ATTRIBUTE_NORMAL, 191 FILE_SHARE_READ | FILE_SHARE_WRITE, 192 FILE_OPEN, 193 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT, 194 NULL, 195 0, 196 CreateFileTypeNone, 197 NULL, 198 IO_NO_PARAMETER_CHECKING | (gNoLinks ? IO_STOP_ON_SYMLINK : 0)); 199 if (NT_SUCCESS(Status)) 200 { 201 NTSTATUS IntStatus; 202 203 IntStatus = ObReferenceObjectByHandle(Handle, 204 FILE_READ_DATA, 205 *IoFileObjectType, 206 KernelMode, 207 (PVOID *)&FileObject, 208 NULL); 209 ok_eq_hex(IntStatus, STATUS_SUCCESS); 210 if (NT_SUCCESS(IntStatus)) 211 { 212 ok(RtlCompareUnicodeString(&FileObjectFileName, &FileObject->FileName, TRUE) == 0 || 213 RtlCompareUnicodeString(&DocumentsAndSettings, &FileObject->FileName, TRUE) == 0, 214 "Expected: %wZ or %wZ. Opened: %wZ\n", &FileObjectFileName, &DocumentsAndSettings, &FileObject->FileName); 215 ObDereferenceObject(FileObject); 216 } 217 218 IntStatus = ObCloseHandle(Handle, KernelMode); 219 ok_eq_hex(IntStatus, STATUS_SUCCESS); 220 } 221 222 return Status; 223 } 224 225 static 226 NTSTATUS 227 TestMessageHandler( 228 IN PDEVICE_OBJECT DeviceObject, 229 IN ULONG ControlCode, 230 IN PVOID Buffer OPTIONAL, 231 IN SIZE_T InLength, 232 IN OUT PSIZE_T OutLength) 233 { 234 NTSTATUS Status = STATUS_SUCCESS; 235 236 PAGED_CODE(); 237 238 switch (ControlCode) 239 { 240 case IOCTL_DISABLE_SYMLINK: 241 { 242 if (InterlockedExchange(&gNoLinks, TRUE) == TRUE) 243 { 244 Status = STATUS_UNSUCCESSFUL; 245 } 246 247 break; 248 } 249 case IOCTL_CALL_CREATE: 250 { 251 ANSI_STRING Path; 252 UNICODE_STRING PathW; 253 254 ok(Buffer != NULL, "Buffer is NULL\n"); 255 Path.Length = Path.MaximumLength = (USHORT)InLength; 256 Path.Buffer = Buffer; 257 258 Status = RtlAnsiStringToUnicodeString(&PathW, &Path, TRUE); 259 ok_eq_hex(Status, STATUS_SUCCESS); 260 261 Status = TestIoCreateFile(&PathW); 262 263 RtlFreeUnicodeString(&PathW); 264 265 break; 266 } 267 default: 268 return STATUS_NOT_SUPPORTED; 269 } 270 271 return Status; 272 } 273