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