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
TestEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PCUNICODE_STRING RegistryPath,_Out_ PCWSTR * DeviceName,_Inout_ INT * Flags)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
TestUnload(_In_ PDRIVER_OBJECT DriverObject)54 TestUnload(
55 _In_ PDRIVER_OBJECT DriverObject)
56 {
57 PAGED_CODE();
58 }
59
60 static volatile long gNoLinks = FALSE;
61
62 static
63 NTSTATUS
TestIrpHandler(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp,_In_ PIO_STACK_LOCATION IoStack)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
TestIoCreateFile(IN PUNICODE_STRING Path)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
TestMessageHandler(IN PDEVICE_OBJECT DeviceObject,IN ULONG ControlCode,IN PVOID Buffer OPTIONAL,IN SIZE_T InLength,IN OUT PSIZE_T OutLength)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