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 = ExAllocatePoolZero(NonPagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 'FwrI'); 98 Reparse = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; 99 100 if (!Reparse) 101 { 102 Status = STATUS_INSUFFICIENT_RESOURCES; 103 goto Finish; 104 } 105 106 Reparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; 107 Reparse->ReparseDataLength = 12 + sizeof(L"\\??\\C:\\Documents and Settings"); 108 Reparse->MountPointReparseBuffer.SubstituteNameLength = sizeof(L"\\??\\C:\\Documents and Settings") - sizeof(UNICODE_NULL); 109 Reparse->MountPointReparseBuffer.PrintNameOffset = sizeof(L"\\??\\C:\\Documents and Settings"); 110 RtlCopyMemory(Reparse->MountPointReparseBuffer.PathBuffer, L"\\??\\C:\\Documents and Settings", sizeof(L"\\??\\C:\\Documents and Settings")); 111 Irp->IoStatus.Information = IO_REPARSE_TAG_MOUNT_POINT; 112 Status = STATUS_REPARSE; 113 } 114 else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && 115 IoStack->FileObject->FileName.Buffer[1] == 'S') 116 { 117 PREPARSE_DATA_BUFFER Reparse; 118 119 if (IoStack->Flags & SL_STOP_ON_SYMLINK) 120 { 121 Status = STATUS_STOPPED_ON_SYMLINK; 122 goto Finish; 123 } 124 125 Irp->Tail.Overlay.AuxiliaryBuffer = ExAllocatePoolZero(NonPagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, 'FwrI'); 126 Reparse = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; 127 128 if (!Reparse) 129 { 130 Status = STATUS_INSUFFICIENT_RESOURCES; 131 goto Finish; 132 } 133 134 Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK; 135 Reparse->ReparseDataLength = 12 + sizeof(L"\\??\\C:\\Documents and Settings"); 136 Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength = sizeof(L"\\??\\C:\\Documents and Settings") - sizeof(UNICODE_NULL); 137 Reparse->SymbolicLinkReparseBuffer.PrintNameOffset = sizeof(L"\\??\\C:\\Documents and Settings"); 138 RtlCopyMemory(Reparse->SymbolicLinkReparseBuffer.PathBuffer, L"\\??\\C:\\Documents and Settings", sizeof(L"\\??\\C:\\Documents and Settings")); 139 Irp->IoStatus.Information = IO_REPARSE_TAG_SYMLINK; 140 Status = STATUS_REPARSE; 141 } 142 else 143 { 144 Fcb = ExAllocatePoolZero(NonPagedPool, sizeof(*Fcb), 'FwrI'); 145 146 if (!Fcb) 147 { 148 Status = STATUS_INSUFFICIENT_RESOURCES; 149 goto Finish; 150 } 151 152 ExInitializeFastMutex(&Fcb->HeaderMutex); 153 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex); 154 Fcb->Header.AllocationSize.QuadPart = 0; 155 Fcb->Header.FileSize.QuadPart = 0; 156 Fcb->Header.ValidDataLength.QuadPart = 0; 157 IoStack->FileObject->FsContext = Fcb; 158 IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; 159 160 Irp->IoStatus.Information = FILE_OPENED; 161 Status = STATUS_SUCCESS; 162 } 163 } 164 else if (IoStack->MajorFunction == IRP_MJ_CLEANUP) 165 { 166 KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE); 167 CcUninitializeCacheMap(IoStack->FileObject, NULL, &CacheUninitEvent); 168 KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL); 169 Fcb = IoStack->FileObject->FsContext; 170 ExFreePoolWithTag(Fcb, 'FwrI'); 171 IoStack->FileObject->FsContext = NULL; 172 Status = STATUS_SUCCESS; 173 } 174 175 Finish: 176 Irp->IoStatus.Status = Status; 177 IoCompleteRequest(Irp, IO_NO_INCREMENT); 178 179 return Status; 180 } 181 182 static UNICODE_STRING FileObjectFileName = RTL_CONSTANT_STRING(L"\\NonSymlinked"); 183 static UNICODE_STRING DocumentsAndSettings = RTL_CONSTANT_STRING(L"\\Documents and Settings"); 184 185 static 186 NTSTATUS 187 TestIoCreateFile( 188 IN PUNICODE_STRING Path) 189 { 190 OBJECT_ATTRIBUTES ObjectAttributes; 191 IO_STATUS_BLOCK IoStatusBlock; 192 HANDLE Handle; 193 NTSTATUS Status; 194 PFILE_OBJECT FileObject; 195 196 InitializeObjectAttributes(&ObjectAttributes, 197 Path, 198 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 199 NULL, 200 NULL); 201 Status = IoCreateFile(&Handle, 202 GENERIC_READ, 203 &ObjectAttributes, 204 &IoStatusBlock, 205 NULL, 206 FILE_ATTRIBUTE_NORMAL, 207 FILE_SHARE_READ | FILE_SHARE_WRITE, 208 FILE_OPEN, 209 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT, 210 NULL, 211 0, 212 CreateFileTypeNone, 213 NULL, 214 IO_NO_PARAMETER_CHECKING | (gNoLinks ? IO_STOP_ON_SYMLINK : 0)); 215 if (NT_SUCCESS(Status)) 216 { 217 NTSTATUS IntStatus; 218 219 IntStatus = ObReferenceObjectByHandle(Handle, 220 FILE_READ_DATA, 221 *IoFileObjectType, 222 KernelMode, 223 (PVOID *)&FileObject, 224 NULL); 225 ok_eq_hex(IntStatus, STATUS_SUCCESS); 226 if (NT_SUCCESS(IntStatus)) 227 { 228 ok(RtlCompareUnicodeString(&FileObjectFileName, &FileObject->FileName, TRUE) == 0 || 229 RtlCompareUnicodeString(&DocumentsAndSettings, &FileObject->FileName, TRUE) == 0, 230 "Expected: %wZ or %wZ. Opened: %wZ\n", &FileObjectFileName, &DocumentsAndSettings, &FileObject->FileName); 231 ObDereferenceObject(FileObject); 232 } 233 234 IntStatus = ObCloseHandle(Handle, KernelMode); 235 ok_eq_hex(IntStatus, STATUS_SUCCESS); 236 } 237 238 return Status; 239 } 240 241 static 242 NTSTATUS 243 TestMessageHandler( 244 IN PDEVICE_OBJECT DeviceObject, 245 IN ULONG ControlCode, 246 IN PVOID Buffer OPTIONAL, 247 IN SIZE_T InLength, 248 IN OUT PSIZE_T OutLength) 249 { 250 NTSTATUS Status = STATUS_SUCCESS; 251 252 PAGED_CODE(); 253 254 switch (ControlCode) 255 { 256 case IOCTL_DISABLE_SYMLINK: 257 { 258 if (InterlockedExchange(&gNoLinks, TRUE) == TRUE) 259 { 260 Status = STATUS_UNSUCCESSFUL; 261 } 262 263 break; 264 } 265 case IOCTL_CALL_CREATE: 266 { 267 ANSI_STRING Path; 268 UNICODE_STRING PathW; 269 270 ok(Buffer != NULL, "Buffer is NULL\n"); 271 Path.Length = Path.MaximumLength = (USHORT)InLength; 272 Path.Buffer = Buffer; 273 274 Status = RtlAnsiStringToUnicodeString(&PathW, &Path, TRUE); 275 ok_eq_hex(Status, STATUS_SUCCESS); 276 277 Status = TestIoCreateFile(&PathW); 278 279 RtlFreeUnicodeString(&PathW); 280 281 break; 282 } 283 default: 284 return STATUS_NOT_SUPPORTED; 285 } 286 287 return Status; 288 } 289