1 /*
2  * PROJECT:     ReactOS kernel-mode tests
3  * LICENSE:     LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4  * PURPOSE:     Test driver for kernel32 filesystem tests
5  * COPYRIGHT:   Copyright 2013-2017 Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 #include "kernel32_test.h"
14 
15 static KMT_MESSAGE_HANDLER TestMessageHandler;
16 static KMT_IRP_HANDLER TestDirectoryControl;
17 static KMT_IRP_HANDLER TestQueryInformation;
18 static KMT_IRP_HANDLER TestSetInformation;
19 
20 static UNICODE_STRING ExpectedExpression = RTL_CONSTANT_STRING(L"<not set>");
21 static WCHAR ExpressionBuffer[MAX_PATH];
22 static BOOLEAN ExpectingSetAttributes = FALSE;
23 static ULONG ExpectedSetAttributes = -1;
24 static BOOLEAN ExpectingQueryAttributes = FALSE;
25 static ULONG ReturnQueryAttributes = -1;
26 
27 NTSTATUS
28 TestEntry(
29     IN PDRIVER_OBJECT DriverObject,
30     IN PCUNICODE_STRING RegistryPath,
31     OUT PCWSTR *DeviceName,
32     IN OUT INT *Flags)
33 {
34     NTSTATUS Status = STATUS_SUCCESS;
35 
36     PAGED_CODE();
37 
38     UNREFERENCED_PARAMETER(RegistryPath);
39 
40     *DeviceName = L"kernel32";
41     *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE;
42 
43     KmtRegisterIrpHandler(IRP_MJ_DIRECTORY_CONTROL, NULL, TestDirectoryControl);
44     KmtRegisterIrpHandler(IRP_MJ_QUERY_INFORMATION, NULL, TestQueryInformation);
45     KmtRegisterIrpHandler(IRP_MJ_SET_INFORMATION, NULL, TestSetInformation);
46     KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
47 
48     return Status;
49 }
50 
51 VOID
52 TestUnload(
53     IN PDRIVER_OBJECT DriverObject)
54 {
55     PAGED_CODE();
56 }
57 
58 static
59 NTSTATUS
60 TestMessageHandler(
61     IN PDEVICE_OBJECT DeviceObject,
62     IN ULONG ControlCode,
63     IN PVOID Buffer OPTIONAL,
64     IN SIZE_T InLength,
65     IN OUT PSIZE_T OutLength)
66 {
67     NTSTATUS Status = STATUS_SUCCESS;
68 
69     PAGED_CODE();
70 
71     switch (ControlCode)
72     {
73         case IOCTL_EXPECT_EXPRESSION:
74         {
75             C_ASSERT(sizeof(ExpressionBuffer) <= UNICODE_STRING_MAX_BYTES);
76             DPRINT("IOCTL_EXPECT_EXPRESSION, InLength = %lu\n", InLength);
77             if (InLength > sizeof(ExpressionBuffer))
78                 return STATUS_BUFFER_OVERFLOW;
79 
80             if (InLength % sizeof(WCHAR) != 0)
81                 return STATUS_INVALID_PARAMETER;
82 
83             RtlInitEmptyUnicodeString(&ExpectedExpression, ExpressionBuffer, sizeof(ExpressionBuffer));
84             RtlCopyMemory(ExpressionBuffer, Buffer, InLength);
85             ExpectedExpression.Length = (USHORT)InLength;
86             DPRINT("IOCTL_EXPECT_EXPRESSION: %wZ\n", &ExpectedExpression);
87 
88             break;
89         }
90         case IOCTL_RETURN_QUERY_ATTRIBUTES:
91         {
92             DPRINT("IOCTL_RETURN_QUERY_ATTRIBUTES, InLength = %lu\n", InLength);
93             if (InLength != sizeof(ULONG))
94                 return STATUS_INVALID_PARAMETER;
95 
96             ReturnQueryAttributes = *(PULONG)Buffer;
97             ExpectingQueryAttributes = TRUE;
98             DPRINT("IOCTL_RETURN_QUERY_ATTRIBUTES: %lu\n", ReturnQueryAttributes);
99             break;
100         }
101         case IOCTL_EXPECT_SET_ATTRIBUTES:
102         {
103             DPRINT("IOCTL_EXPECT_SET_ATTRIBUTES, InLength = %lu\n", InLength);
104             if (InLength != sizeof(ULONG))
105                 return STATUS_INVALID_PARAMETER;
106 
107             ExpectedSetAttributes = *(PULONG)Buffer;
108             ExpectingSetAttributes = TRUE;
109             DPRINT("IOCTL_EXPECT_SET_ATTRIBUTES: %lu\n", ExpectedSetAttributes);
110             break;
111         }
112         default:
113             return STATUS_NOT_SUPPORTED;
114     }
115 
116     return Status;
117 }
118 
119 static
120 NTSTATUS
121 TestDirectoryControl(
122     IN PDEVICE_OBJECT DeviceObject,
123     IN PIRP Irp,
124     IN PIO_STACK_LOCATION IoStackLocation)
125 {
126     NTSTATUS Status = STATUS_NOT_SUPPORTED;
127 
128     PAGED_CODE();
129 
130     DPRINT("IRP %x/%x\n", IoStackLocation->MajorFunction, IoStackLocation->MinorFunction);
131     ASSERT(IoStackLocation->MajorFunction == IRP_MJ_DIRECTORY_CONTROL);
132 
133     ok(IoStackLocation->MinorFunction == IRP_MN_QUERY_DIRECTORY, "Minor function: %u\n", IoStackLocation->MinorFunction);
134     if (IoStackLocation->MinorFunction == IRP_MN_QUERY_DIRECTORY)
135     {
136         ok(IoStackLocation->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation,
137            "FileInformationClass: %d\n", IoStackLocation->Parameters.QueryDirectory.FileInformationClass);
138         if (IoStackLocation->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation)
139         {
140             ok(RtlEqualUnicodeString(IoStackLocation->Parameters.QueryDirectory.FileName, &ExpectedExpression, FALSE),
141                "Expression is '%wZ', expected '%wZ'\n", IoStackLocation->Parameters.QueryDirectory.FileName, &ExpectedExpression);
142             RtlZeroMemory(Irp->UserBuffer, IoStackLocation->Parameters.QueryDirectory.Length);
143             Status = STATUS_SUCCESS;
144         }
145     }
146 
147     Irp->IoStatus.Status = Status;
148     Irp->IoStatus.Information = 0;
149 
150     IoCompleteRequest(Irp, IO_NO_INCREMENT);
151 
152     return Status;
153 }
154 
155 static
156 NTSTATUS
157 TestQueryInformation(
158     IN PDEVICE_OBJECT DeviceObject,
159     IN PIRP Irp,
160     IN PIO_STACK_LOCATION IoStackLocation)
161 {
162     NTSTATUS Status = STATUS_NOT_SUPPORTED;
163     PFILE_BASIC_INFORMATION BasicInfo;
164 
165     PAGED_CODE();
166 
167     DPRINT("IRP %x/%x\n", IoStackLocation->MajorFunction, IoStackLocation->MinorFunction);
168     ASSERT(IoStackLocation->MajorFunction == IRP_MJ_QUERY_INFORMATION);
169 
170     Irp->IoStatus.Information = 0;
171 
172     ok_eq_ulong(IoStackLocation->Parameters.QueryFile.FileInformationClass, FileBasicInformation);
173     if (IoStackLocation->Parameters.QueryFile.FileInformationClass == FileBasicInformation)
174     {
175         ok(ExpectingQueryAttributes, "Unexpected QUERY_INFORMATION call\n");
176         BasicInfo = Irp->AssociatedIrp.SystemBuffer;
177         BasicInfo->CreationTime.QuadPart = 126011664000000000;
178         BasicInfo->LastAccessTime.QuadPart = 130899112800000000;
179         BasicInfo->LastWriteTime.QuadPart = 130899112800000000;
180         BasicInfo->ChangeTime.QuadPart = 130899112800000000;
181         BasicInfo->FileAttributes = ReturnQueryAttributes;
182         ReturnQueryAttributes = -1;
183         ExpectingQueryAttributes = FALSE;
184         Status = STATUS_SUCCESS;
185         Irp->IoStatus.Information = sizeof(*BasicInfo);
186     }
187 
188     Irp->IoStatus.Status = Status;
189 
190     IoCompleteRequest(Irp, IO_NO_INCREMENT);
191 
192     return Status;
193 }
194 
195 static
196 NTSTATUS
197 TestSetInformation(
198     IN PDEVICE_OBJECT DeviceObject,
199     IN PIRP Irp,
200     IN PIO_STACK_LOCATION IoStackLocation)
201 {
202     NTSTATUS Status = STATUS_NOT_SUPPORTED;
203     PFILE_BASIC_INFORMATION BasicInfo;
204 
205     PAGED_CODE();
206 
207     DPRINT("IRP %x/%x\n", IoStackLocation->MajorFunction, IoStackLocation->MinorFunction);
208     ASSERT(IoStackLocation->MajorFunction == IRP_MJ_SET_INFORMATION);
209 
210     ok_eq_ulong(IoStackLocation->Parameters.SetFile.FileInformationClass, FileBasicInformation);
211     if (IoStackLocation->Parameters.SetFile.FileInformationClass == FileBasicInformation)
212     {
213         ok(ExpectingSetAttributes, "Unexpected SET_INFORMATION call\n");
214         BasicInfo = Irp->AssociatedIrp.SystemBuffer;
215         ok_eq_longlong(BasicInfo->CreationTime.QuadPart, 0LL);
216         ok_eq_longlong(BasicInfo->LastAccessTime.QuadPart, 0LL);
217         ok_eq_longlong(BasicInfo->LastWriteTime.QuadPart, 0LL);
218         ok_eq_longlong(BasicInfo->ChangeTime.QuadPart, 0LL);
219         ok_eq_ulong(BasicInfo->FileAttributes, ExpectedSetAttributes);
220         ExpectedSetAttributes = -1;
221         ExpectingSetAttributes = FALSE;
222         Status = STATUS_SUCCESS;
223     }
224 
225     Irp->IoStatus.Status = Status;
226     Irp->IoStatus.Information = 0;
227 
228     IoCompleteRequest(Irp, IO_NO_INCREMENT);
229 
230     return Status;
231 }
232