* Sync with trunk r64401.
[reactos.git] / drivers / filesystems / npfs / main.c
1 /*
2 * PROJECT: ReactOS Named Pipe FileSystem
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/filesystems/npfs/main.c
5 * PURPOSE: Named Pipe FileSystem Driver Initialization
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "npfs.h"
12
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_MAIN)
15
16 /* GLOBALS ********************************************************************/
17
18 PDEVICE_OBJECT NpfsDeviceObject;
19 PVOID NpAliases;
20 PNPFS_ALIAS NpAliasList;
21 PNPFS_ALIAS NpAliasListByLength[MAX_INDEXED_LENGTH + 1 - MIN_INDEXED_LENGTH];
22
23 FAST_IO_DISPATCH NpFastIoDispatch =
24 {
25 sizeof(FAST_IO_DISPATCH),
26 NULL,
27 NpFastRead,
28 NpFastWrite,
29 };
30
31 /* FUNCTIONS ******************************************************************/
32
33 NTSTATUS
34 NTAPI
35 NpReadAlias(
36 PWSTR ValueName,
37 ULONG ValueType,
38 PVOID ValueData,
39 ULONG ValueLength,
40 PVOID Context,
41 PVOID EntryContext)
42 {
43 PNPFS_QUERY_VALUE_CONTEXT QueryContext = Context;
44 PWSTR CurrentString;
45 USHORT Length;
46 PNPFS_ALIAS CurrentAlias;
47 UNICODE_STRING TempString;
48 PUNICODE_STRING CurrentTargetName;
49
50 /* Check if we have the expected type */
51 if (ValueType != REG_MULTI_SZ)
52 {
53 return STATUS_INVALID_PARAMETER;
54 }
55
56 /* Check if only the size is requested */
57 if (QueryContext->SizeOnly)
58 {
59 /* Count this entry */
60 QueryContext->NumberOfEntries++;
61
62 /* Get the length of the value name (i.e. the target name). */
63 Length = wcslen(ValueName) * sizeof(WCHAR);
64
65 /* Add the size of the name plus a '\' and a UNICODE_STRING structure */
66 QueryContext->FullSize += Length + sizeof(UNICODE_NULL) +
67 sizeof(OBJ_NAME_PATH_SEPARATOR) +
68 sizeof(UNICODE_STRING);
69
70 /* Loop while we have alias names */
71 CurrentString = ValueData;
72 while (*CurrentString != UNICODE_NULL)
73 {
74 /* Count this alias */
75 QueryContext->NumberOfAliases++;
76
77 /* Get the length of the current string (i.e. the alias name) */
78 Length = wcslen(CurrentString) * sizeof(WCHAR);
79
80 /* Count the length plus the size of an NPFS_ALIAS structure */
81 QueryContext->FullSize += Length + sizeof(UNICODE_NULL) + sizeof(NPFS_ALIAS);
82
83 /* Go to the next string */
84 CurrentString += (Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
85 }
86 }
87 else
88 {
89 /* Get the next name string pointer */
90 CurrentTargetName = QueryContext->CurrentTargetName++;
91
92 /* Get the length of the value name (i.e. the target name). */
93 Length = wcslen(ValueName) * sizeof(WCHAR);
94
95 /* Initialize the current name string (one char more than the name) */
96 CurrentTargetName->Buffer = QueryContext->CurrentStringPointer;
97 CurrentTargetName->Length = Length + sizeof(OBJ_NAME_PATH_SEPARATOR);
98 CurrentTargetName->MaximumLength = CurrentTargetName->Length + sizeof(UNICODE_NULL);
99
100 /* Update the current string pointer */
101 QueryContext->CurrentStringPointer +=
102 CurrentTargetName->MaximumLength / sizeof(WCHAR);
103
104 /* Prepend a '\' before the name */
105 CurrentTargetName->Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
106
107 /* Append the value name (including the NULL termination) */
108 RtlCopyMemory(&CurrentTargetName->Buffer[1],
109 ValueName,
110 Length + sizeof(UNICODE_NULL));
111
112 /* Upcase the target name */
113 RtlUpcaseUnicodeString(CurrentTargetName, CurrentTargetName, 0);
114
115 /* Loop while we have alias names */
116 CurrentString = ValueData;
117 while (*CurrentString != UNICODE_NULL)
118 {
119 /* Get the next alias pointer */
120 CurrentAlias = QueryContext->CurrentAlias++;
121
122 /* Get the length of the current string (i.e. the alias name) */
123 Length = wcslen(CurrentString) * sizeof(WCHAR);
124
125 /* Setup the alias structure */
126 CurrentAlias->TargetName = CurrentTargetName;
127 CurrentAlias->Name.Buffer = QueryContext->CurrentStringPointer;
128 CurrentAlias->Name.Length = Length;
129 CurrentAlias->Name.MaximumLength = Length + sizeof(UNICODE_NULL);
130
131 /* Upcase the alias name */
132 TempString.Buffer = CurrentString;
133 TempString.Length = Length;
134 RtlUpcaseUnicodeString(&CurrentAlias->Name,
135 &TempString,
136 FALSE);
137
138 /* Update the current string pointer */
139 QueryContext->CurrentStringPointer +=
140 CurrentAlias->Name.MaximumLength / sizeof(WCHAR);
141
142 /* Go to the next string */
143 CurrentString += (Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
144 }
145 }
146
147 return STATUS_SUCCESS;
148 }
149
150 LONG
151 NTAPI
152 NpCompareAliasNames(
153 _In_ PCUNICODE_STRING String1,
154 _In_ PCUNICODE_STRING String2)
155 {
156 ULONG Count;
157 PWCHAR P1, P2;
158
159 /* First check if the string sizes match */
160 if (String1->Length != String2->Length)
161 {
162 /* They don't, return positive if the first is longer, negative otherwise */
163 return String1->Length - String2->Length;
164 }
165
166 /* Now loop all characters */
167 Count = String1->Length / sizeof(WCHAR);
168 P1 = String1->Buffer;
169 P2 = String2->Buffer;
170 while (Count)
171 {
172 /* Check if they don't match */
173 if (*P1 != *P2)
174 {
175 /* Return positive if the first char is greater, negative otherwise */
176 return *P1 - *P2;
177 }
178
179 /* Go to the next buffer position */
180 P1++;
181 P2++;
182 Count--;
183 }
184
185 /* All characters matched, return 0 */
186 return 0;
187 }
188
189 NTSTATUS
190 NTAPI
191 NpInitializeAliases(VOID)
192 {
193 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
194 NPFS_QUERY_VALUE_CONTEXT Context;
195 NTSTATUS Status;
196 USHORT Length;
197 ULONG i;
198 PNPFS_ALIAS CurrentAlias, *AliasPointer;
199
200 /* Initialize the query table */
201 QueryTable[0].QueryRoutine = NpReadAlias;
202 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
203 QueryTable[0].Name = NULL;
204 QueryTable[0].EntryContext = NULL;
205 QueryTable[0].DefaultType = REG_NONE;
206 QueryTable[0].DefaultData = NULL;
207 QueryTable[0].DefaultLength = 0;
208 QueryTable[1].QueryRoutine = NULL;
209 QueryTable[1].Flags = 0;
210 QueryTable[1].Name = NULL;
211
212 /* Setup the query context */
213 Context.SizeOnly = 1;
214 Context.FullSize = 0;
215 Context.NumberOfAliases = 0;
216 Context.NumberOfEntries = 0;
217
218 /* Query the registry values (calculate length only) */
219 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
220 L"Npfs\\Aliases",
221 QueryTable,
222 &Context,
223 NULL);
224 if (!NT_SUCCESS(Status))
225 {
226 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
227 return STATUS_SUCCESS;
228
229 return Status;
230 }
231
232 /* Check if there is anything */
233 if (Context.FullSize == 0)
234 {
235 /* Nothing to do, return success */
236 return STATUS_SUCCESS;
237 }
238
239 /* Allocate a structure large enough to hold all the data */
240 NpAliases = ExAllocatePoolWithTag(NonPagedPool, Context.FullSize, 'sfpN');
241 if (NpAliases == NULL)
242 return STATUS_INSUFFICIENT_RESOURCES;
243
244 /* Now setup the actual pointers in the context */
245 Context.CurrentTargetName = NpAliases;
246 CurrentAlias = (PNPFS_ALIAS)&Context.CurrentTargetName[Context.NumberOfEntries];
247 Context.CurrentAlias = CurrentAlias;
248 Context.CurrentStringPointer = (PWCHAR)&CurrentAlias[Context.NumberOfAliases];
249
250 /* This time query the real data */
251 Context.SizeOnly = FALSE;
252 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
253 L"Npfs\\Aliases",
254 QueryTable,
255 &Context,
256 NULL);
257 if (!NT_SUCCESS(Status))
258 {
259 ExFreePoolWithTag(NpAliases, 0);
260 NpAliases = NULL;
261 return Status;
262 }
263
264 /* Make sure we didn't go past the end of the allocation! */
265 NT_ASSERT((PUCHAR)Context.CurrentStringPointer <=
266 ((PUCHAR)NpAliases + Context.FullSize));
267
268 /* Loop all aliases we got */
269 for (i = 0; i < Context.NumberOfAliases; i++)
270 {
271 /* Get the length and check what list to use */
272 Length = CurrentAlias->Name.Length;
273 if ((Length >= MIN_INDEXED_LENGTH * sizeof(WCHAR)) &&
274 (Length <= MAX_INDEXED_LENGTH * sizeof(WCHAR)))
275 {
276 /* For this length range, we use an indexed list */
277 AliasPointer = &NpAliasListByLength[(Length / sizeof(WCHAR)) - 5];
278 }
279 else
280 {
281 /* Length is outside of the range, use the default list */
282 AliasPointer = &NpAliasList;
283 }
284
285 /* Loop through all aliases already in the list until we find one that
286 is greater than our current alias */
287 while ((*AliasPointer != NULL) &&
288 (NpCompareAliasNames(&CurrentAlias->Name,
289 &(*AliasPointer)->Name) > 0))
290 {
291 /* Go to the next alias */
292 AliasPointer = &(*AliasPointer)->Next;
293 }
294
295 /* Insert the alias in the list */
296 CurrentAlias->Next = *AliasPointer;
297 *AliasPointer = CurrentAlias;
298
299 /* Go to the next alias in the array */
300 CurrentAlias++;
301 }
302
303 return STATUS_SUCCESS;
304 }
305
306
307 NTSTATUS
308 NTAPI
309 NpFsdDirectoryControl(IN PDEVICE_OBJECT DeviceObject,
310 IN PIRP Irp)
311 {
312 TRACE("Entered\n");
313 UNIMPLEMENTED;
314
315 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
316 Irp->IoStatus.Information = 0;
317
318 IoCompleteRequest(Irp, IO_NO_INCREMENT);
319 return STATUS_NOT_IMPLEMENTED;
320 }
321
322
323 NTSTATUS
324 NTAPI
325 DriverEntry(IN PDRIVER_OBJECT DriverObject,
326 IN PUNICODE_STRING RegistryPath)
327 {
328 PDEVICE_OBJECT DeviceObject;
329 UNICODE_STRING DeviceName;
330 NTSTATUS Status;
331 UNREFERENCED_PARAMETER(RegistryPath);
332
333 DPRINT("Next-Generation NPFS-Advanced\n");
334
335 Status = NpInitializeAliases();
336 if (!NT_SUCCESS(Status))
337 {
338 DPRINT1("Failed to initialize aliases!\n");
339 return Status;
340 }
341
342 DriverObject->MajorFunction[IRP_MJ_CREATE] = NpFsdCreate;
343 DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = NpFsdCreateNamedPipe;
344 DriverObject->MajorFunction[IRP_MJ_CLOSE] = NpFsdClose;
345 DriverObject->MajorFunction[IRP_MJ_READ] = NpFsdRead;
346 DriverObject->MajorFunction[IRP_MJ_WRITE] = NpFsdWrite;
347 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = NpFsdQueryInformation;
348 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = NpFsdSetInformation;
349 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = NpFsdQueryVolumeInformation;
350 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NpFsdCleanup;
351 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = NpFsdFlushBuffers;
352 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = NpFsdDirectoryControl;
353 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = NpFsdFileSystemControl;
354 DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = NpFsdQuerySecurityInfo;
355 DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = NpFsdSetSecurityInfo;
356
357 DriverObject->DriverUnload = NULL;
358
359 DriverObject->FastIoDispatch = &NpFastIoDispatch;
360
361 RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe");
362 Status = IoCreateDevice(DriverObject,
363 sizeof(NP_VCB),
364 &DeviceName,
365 FILE_DEVICE_NAMED_PIPE,
366 0,
367 FALSE,
368 &DeviceObject);
369 if (!NT_SUCCESS(Status))
370 {
371 DPRINT1("Failed to create named pipe device! (Status %lx)\n", Status);
372 return Status;
373 }
374
375 /* Initialize the device object */
376 NpfsDeviceObject = DeviceObject;
377 DeviceObject->Flags |= DO_LONG_TERM_REQUESTS;
378
379 /* Initialize the Volume Control Block (VCB) */
380 NpVcb = DeviceObject->DeviceExtension;
381 NpInitializeVcb();
382 Status = NpCreateRootDcb();
383 ASSERT(Status == STATUS_SUCCESS);
384 return STATUS_SUCCESS;
385 }
386
387 /* EOF */