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
9 /* INCLUDES *******************************************************************/
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_MAIN)
16 /* GLOBALS ********************************************************************/
18 PDEVICE_OBJECT NpfsDeviceObject
;
20 PNPFS_ALIAS NpAliasList
;
21 PNPFS_ALIAS NpAliasListByLength
[MAX_INDEXED_LENGTH
+ 1 - MIN_INDEXED_LENGTH
];
23 FAST_IO_DISPATCH NpFastIoDispatch
=
25 sizeof(FAST_IO_DISPATCH
),
31 /* FUNCTIONS ******************************************************************/
43 PNPFS_QUERY_VALUE_CONTEXT QueryContext
= Context
;
46 PNPFS_ALIAS CurrentAlias
;
47 UNICODE_STRING TempString
;
48 PUNICODE_STRING CurrentTargetName
;
50 /* Check if we have the expected type */
51 if (ValueType
!= REG_MULTI_SZ
)
53 return STATUS_INVALID_PARAMETER
;
56 /* Check if only the size is requested */
57 if (QueryContext
->SizeOnly
)
59 /* Count this entry */
60 QueryContext
->NumberOfEntries
++;
62 /* Get the length of the value name (i.e. the target name). */
63 Length
= wcslen(ValueName
) * sizeof(WCHAR
);
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
);
70 /* Loop while we have alias names */
71 CurrentString
= ValueData
;
72 while (*CurrentString
!= UNICODE_NULL
)
74 /* Count this alias */
75 QueryContext
->NumberOfAliases
++;
77 /* Get the length of the current string (i.e. the alias name) */
78 Length
= wcslen(CurrentString
) * sizeof(WCHAR
);
80 /* Count the length plus the size of an NPFS_ALIAS structure */
81 QueryContext
->FullSize
+= Length
+ sizeof(UNICODE_NULL
) + sizeof(NPFS_ALIAS
);
83 /* Go to the next string */
84 CurrentString
+= (Length
+ sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
89 /* Get the next name string pointer */
90 CurrentTargetName
= QueryContext
->CurrentTargetName
++;
92 /* Get the length of the value name (i.e. the target name). */
93 Length
= wcslen(ValueName
) * sizeof(WCHAR
);
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
);
100 /* Update the current string pointer */
101 QueryContext
->CurrentStringPointer
+=
102 CurrentTargetName
->MaximumLength
/ sizeof(WCHAR
);
104 /* Prepend a '\' before the name */
105 CurrentTargetName
->Buffer
[0] = OBJ_NAME_PATH_SEPARATOR
;
107 /* Append the value name (including the NULL termination) */
108 RtlCopyMemory(&CurrentTargetName
->Buffer
[1],
110 Length
+ sizeof(UNICODE_NULL
));
112 /* Upcase the target name */
113 RtlUpcaseUnicodeString(CurrentTargetName
, CurrentTargetName
, 0);
115 /* Loop while we have alias names */
116 CurrentString
= ValueData
;
117 while (*CurrentString
!= UNICODE_NULL
)
119 /* Get the next alias pointer */
120 CurrentAlias
= QueryContext
->CurrentAlias
++;
122 /* Get the length of the current string (i.e. the alias name) */
123 Length
= wcslen(CurrentString
) * sizeof(WCHAR
);
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
);
131 /* Upcase the alias name */
132 TempString
.Buffer
= CurrentString
;
133 TempString
.Length
= Length
;
134 RtlUpcaseUnicodeString(&CurrentAlias
->Name
,
138 /* Update the current string pointer */
139 QueryContext
->CurrentStringPointer
+=
140 CurrentAlias
->Name
.MaximumLength
/ sizeof(WCHAR
);
142 /* Go to the next string */
143 CurrentString
+= (Length
+ sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
147 return STATUS_SUCCESS
;
153 _In_ PCUNICODE_STRING String1
,
154 _In_ PCUNICODE_STRING String2
)
159 /* First check if the string sizes match */
160 if (String1
->Length
!= String2
->Length
)
162 /* They don't, return positive if the first is longer, negative otherwise */
163 return String1
->Length
- String2
->Length
;
166 /* Now loop all characters */
167 Count
= String1
->Length
/ sizeof(WCHAR
);
168 P1
= String1
->Buffer
;
169 P2
= String2
->Buffer
;
172 /* Check if they don't match */
175 /* Return positive if the first char is greater, negative otherwise */
179 /* Go to the next buffer position */
185 /* All characters matched, return 0 */
191 NpInitializeAliases(VOID
)
193 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
194 NPFS_QUERY_VALUE_CONTEXT Context
;
198 PNPFS_ALIAS CurrentAlias
, *AliasPointer
;
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
;
212 /* Setup the query context */
213 Context
.SizeOnly
= 1;
214 Context
.FullSize
= 0;
215 Context
.NumberOfAliases
= 0;
216 Context
.NumberOfEntries
= 0;
218 /* Query the registry values (calculate length only) */
219 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
| RTL_REGISTRY_OPTIONAL
,
224 if (!NT_SUCCESS(Status
))
226 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
227 return STATUS_SUCCESS
;
232 /* Check if there is anything */
233 if (Context
.FullSize
== 0)
235 /* Nothing to do, return success */
236 return STATUS_SUCCESS
;
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
;
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
];
250 /* This time query the real data */
251 Context
.SizeOnly
= FALSE
;
252 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
| RTL_REGISTRY_OPTIONAL
,
257 if (!NT_SUCCESS(Status
))
259 ExFreePoolWithTag(NpAliases
, 0);
264 /* Make sure we didn't go past the end of the allocation! */
265 NT_ASSERT((PUCHAR
)Context
.CurrentStringPointer
<=
266 ((PUCHAR
)NpAliases
+ Context
.FullSize
));
268 /* Loop all aliases we got */
269 for (i
= 0; i
< Context
.NumberOfAliases
; i
++)
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
)))
276 /* For this length range, we use an indexed list */
277 AliasPointer
= &NpAliasListByLength
[(Length
/ sizeof(WCHAR
)) - 5];
281 /* Length is outside of the range, use the default list */
282 AliasPointer
= &NpAliasList
;
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))
291 /* Go to the next alias */
292 AliasPointer
= &(*AliasPointer
)->Next
;
295 /* Insert the alias in the list */
296 CurrentAlias
->Next
= *AliasPointer
;
297 *AliasPointer
= CurrentAlias
;
299 /* Go to the next alias in the array */
303 return STATUS_SUCCESS
;
309 NpFsdDirectoryControl(IN PDEVICE_OBJECT DeviceObject
,
315 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
316 Irp
->IoStatus
.Information
= 0;
318 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
319 return STATUS_NOT_IMPLEMENTED
;
325 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
326 IN PUNICODE_STRING RegistryPath
)
328 PDEVICE_OBJECT DeviceObject
;
329 UNICODE_STRING DeviceName
;
331 UNREFERENCED_PARAMETER(RegistryPath
);
333 DPRINT("Next-Generation NPFS-Advanced\n");
335 Status
= NpInitializeAliases();
336 if (!NT_SUCCESS(Status
))
338 DPRINT1("Failed to initialize aliases!\n");
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
;
357 DriverObject
->DriverUnload
= NULL
;
359 DriverObject
->FastIoDispatch
= &NpFastIoDispatch
;
361 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\NamedPipe");
362 Status
= IoCreateDevice(DriverObject
,
365 FILE_DEVICE_NAMED_PIPE
,
369 if (!NT_SUCCESS(Status
))
371 DPRINT1("Failed to create named pipe device! (Status %lx)\n", Status
);
375 /* Initialize the device object */
376 NpfsDeviceObject
= DeviceObject
;
377 DeviceObject
->Flags
|= DO_LONG_TERM_REQUESTS
;
379 /* Initialize the Volume Control Block (VCB) */
380 NpVcb
= DeviceObject
->DeviceExtension
;
382 Status
= NpCreateRootDcb();
383 ASSERT(Status
== STATUS_SUCCESS
);
384 return STATUS_SUCCESS
;