xref: /reactos/drivers/filesystems/npfs/main.c (revision 40462c92)
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 */
388