[USP10_WINETEST] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / rostests / kmtests / ntos_io / IoCreateFile_drv.c
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 }